# SandboxAPIs — Coverage Manifest (GENERATED — do not hand-edit).
#
# Generated by `pnpm manifest:generate` from the vendored provider specs
# (see coverage/provider-pins.yaml), tier-tagged per COVERAGE_MANIFEST_SEED.yaml.
# Rows are READ endpoints (GET/HEAD); the read-only write policy is stated once
# in meta.write_operations (invariant #3). Regeneration is deterministic:
# rows are sorted; same specs + seed → byte-identical output.
#
# `status` is SYNCED FROM CONFORMANCE RESULTS via `pnpm manifest:sync` — never
# hand-edit to green. Tier-1 rows start `planned`; tier 2/3 start `deferred`.
# `retired` is the one status conformance does NOT set: it comes from the spec's
# x-sandboxapis-retired annotation (the provider removed the endpoint), and a
# green test result never clears it — see meta.retired_meaning.
# Rows with `flag: needs-tier-review` fell through to the tier-3 default and
# await human tier assignment (see coverage/GENERATION_REPORT.md).
#
# `mode` is the third axis and the only HAND-EDITED one: it comes from the
# committed overlay coverage/MODES.yaml, keyed by the same row keys the status
# overlay uses. tier is a property of the SPEC operation, status of the TEST
# result, mode of OUR ANSWER — see meta.mode_meaning. A row the overlay does not
# name reads `unclassified`: nobody has judged it yet, and that is countable.
#
# `held` is a LABEL, not a fourth axis and not a mode: a row that is BUILDABLE
# TODAY and deliberately not built, with the blocker NAMED. It qualifies the
# row's `mode` (the eventual disposition) rather than replacing it, and it never
# moves a number: a held row stays uncovered, stays in the badge denominator, and
# goes on answering the coverage 404. It exists so a reader can tell 'nobody has
# looked at this' from 'somebody looked, priced it, and named what it waits on'.
# See meta.held_meaning; enforced by packages/conformance/src/manifest/held.test.ts.
#
# A provider's `git:` rows are the git smart-HTTP transport (SPEC rev 9). They
# are CURATED, not enumerated: git smart-HTTP is a wire protocol and no provider
# OpenAPI describes it (see meta.git_transport). Their statuses are still
# conformance-derived — the git runner drives real pkt-line/packfile responses
# — except the `refused` row, which is `excluded` by read-only policy.

meta:
  spec_rev: 5
  generated_by: manifest:generate
  seed: COVERAGE_MANIFEST_SEED.yaml
  provider_pins: coverage/provider-pins.yaml
  status_vocabulary: [planned, in-progress, green, deviation, deferred, excluded, retired]
  retired_meaning: "the PROVIDER removed this endpoint from its API; live hosts refuse it, and the pinned snapshots frozen before that date still serve it. Set from the spec's x-sandboxapis-retired annotation and never cleared by a conformance green."
  tier_meaning:
    1: "M0 launch bar — the surfaces nearly every integration reads"
    2: "fast-follow (M1)"
    3: "long tail, deferred; tracked openly, never silently missing"
  mode_vocabulary: [derive, generate, empty, refuse, read-only, unclassified]
  mode_source: coverage/MODES.yaml
  mode_meaning:
    derive: "the response is computed from artifact rows that already exist"
    generate: "canon does not carry this yet; the generator will produce it, then derive"
    empty: "the true answer for this universe is an empty collection — reason + reviewed date required"
    refuse: "mirror the provider's OWN refusal (e.g. its 403 for a non-admin token) — reason + reviewed date required"
    read-only: "a write named in the manifest because clients probe it; the read-only 403 IS its final response, and it never joins the badge denominator"
    unclassified: "no human has judged this row yet (DECISIONS 2026-08-29 decision 5; the classification run is task A0.4). NOT the whole story for an `excluded` row: those are neither backlog nor badge (DECISIONS 2026-09-01 call 5) and are counted in the generation report's own (excluded) column, so a row that is both `excluded` and `unclassified` has been judged - it will never be covered - and simply carries no mode. The classification backlog is the `unclassified` column of coverage/GENERATION_REPORT.md, never a grep of this file"
  held_vocabulary: [provenance-pass, data-licensing]
  held_source: coverage/MODES.yaml
  held_definition: "a LABEL on a row that is buildable today and DELIBERATELY not built, naming the blocker. It qualifies the row's `mode` rather than replacing it, requires a reviewed date, and moves no number: a held row is never green/deviation/retired, never `empty`/`refuse`, never `excluded` — it stays uncovered, stays in the badge denominator, and goes on answering the coverage 404."
  held_meaning:
    provenance-pass: "every field needs a stated (A)/(B) provenance ruling before the response can be served honestly. The outstanding work is a review pass over the shape, not a canon entity and not renderer code."
    data-licensing: "the values are VENDOR reference data this project holds no grant to redistribute. Serving needs an independently licensed source, so the outstanding work is a licensing answer, not code."
  held_counts: { github: 5, slack: 0, sentry: 0, circleci: 0, zendesk: 3, gitlab: 0, bitbucket: 0, ado: 0, jira: 0, linear: 0, anthropic: 0, cursor: 0, devin: 0, openai: 0, chatgpt: 0, teams: 0, pagerduty: 0, salesforce: 0, hubspot: 0, buildkite: 1, statuspage: 0, fleet: 9 }
  write_operations:
    policy: "excluded"
    behavior: "provider-shaped read-only error naming the attempted write + roadmap link (invariant #3)"
    counts: { github: 582, slack: 12, sentry: 77, circleci: 50, zendesk: 302, gitlab: 996, bitbucket: 152, ado: 172, jira: 393, linear: 0, anthropic: 11, cursor: 4, devin: 109, openai: 166, chatgpt: 0, teams: 17, pagerduty: 254, salesforce: 10, hubspot: 54, buildkite: 91, statuspage: 74 }
  git_transport:
    policy: "fetch-only"
    behavior: "read-only git smart-HTTP v0 (info/refs + git-upload-pack) served from the API host; git-receive-pack is refused by the same read-only boundary as every other write (invariant #3)"
    path_shape: "<api-host>/{owner}/{repo}.git/… — the single-host collapse, recorded as a bounded invariant-#2 exception in SPEC rev 9 and DECISIONS 2026-08-23"
    shape_truth: "git's own wire protocol (gitprotocol-http, gitprotocol-pack). No provider OpenAPI describes these paths, so the rows are curated rather than enumerated; statuses still come from the conformance runner, which validates pkt-line framing and packfile integrity."
    served_by: [github]
    not_served_by: [gitlab, bitbucket, ado] # git hosts we mirror where the transport is not wired up yet
  rest_dialects:
    jira: "every covered /rest/api/3 path is also served at /rest/api/2. Real Jira Cloud serves both; the dialect differs in rich text (v3 ADF documents, v2 plain strings) and in self links (each version echoes the version that was called), and the renderer downgrades both rather than aliasing blindly. Not enumerated as separate rows: the v2 request is rewritten onto the v3 handler, so a v2 row could never differ from its v3 row. DECISIONS 2026-08-30."
  counts:
    github: { rest_read_endpoints: 635, graphql_entities: 13, tier1: 158, tier2: 190, tier3: 287 }
    slack: { rest_read_endpoints: 22, graphql_entities: 0, tier1: 14, tier2: 3, tier3: 5 }
    sentry: { rest_read_endpoints: 86, graphql_entities: 0, tier1: 55, tier2: 17, tier3: 14 }
    circleci: { rest_read_endpoints: 61, graphql_entities: 0, tier1: 22, tier2: 27, tier3: 12 }
    zendesk: { rest_read_endpoints: 343, graphql_entities: 0, tier1: 117, tier2: 119, tier3: 107 }
    gitlab: { rest_read_endpoints: 743, graphql_entities: 12, tier1: 205, tier2: 86, tier3: 452 }
    bitbucket: { rest_read_endpoints: 179, graphql_entities: 0, tier1: 72, tier2: 55, tier3: 52 }
    ado: { rest_read_endpoints: 232, graphql_entities: 0, tier1: 85, tier2: 62, tier3: 85 }
    jira: { rest_read_endpoints: 328, graphql_entities: 0, tier1: 115, tier2: 41, tier3: 172 }
    linear: { rest_read_endpoints: 0, graphql_entities: 17, tier1: 0, tier2: 0, tier3: 0 }
    anthropic: { rest_read_endpoints: 13, graphql_entities: 0, tier1: 12, tier2: 1, tier3: 0 }
    cursor: { rest_read_endpoints: 21, graphql_entities: 0, tier1: 14, tier2: 7, tier3: 0 }
    devin: { rest_read_endpoints: 122, graphql_entities: 0, tier1: 50, tier2: 9, tier3: 63 }
    openai: { rest_read_endpoints: 122, graphql_entities: 0, tier1: 29, tier2: 1, tier3: 92 }
    chatgpt: { rest_read_endpoints: 3, graphql_entities: 0, tier1: 3, tier2: 0, tier3: 0 }
    teams: { rest_read_endpoints: 13, graphql_entities: 0, tier1: 13, tier2: 0, tier3: 0 }
    pagerduty: { rest_read_endpoints: 211, graphql_entities: 0, tier1: 57, tier2: 58, tier3: 96 }
    salesforce: { rest_read_endpoints: 50, graphql_entities: 0, tier1: 16, tier2: 13, tier3: 21 }
    hubspot: { rest_read_endpoints: 32, graphql_entities: 0, tier1: 16, tier2: 16, tier3: 0 }
    buildkite: { rest_read_endpoints: 78, graphql_entities: 0, tier1: 19, tier2: 23, tier3: 36 }
    statuspage: { rest_read_endpoints: 38, graphql_entities: 0, tier1: 11, tier2: 11, tier3: 16 }
    flagged_for_tier_review: { rest: 472, graphql: 0 }
  coverage_badge:
    formula: "terminal(row) := status in {green, deviation} or status = retired or (mode in {empty, refuse} with a reason and a reviewed date); badge := terminal read rows / non-excluded read rows. FULL READ COVERAGE is ratio 1.0."
    denominator: "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."
    thresholds: { Full: 1, Deep: 0.6, Partial: 0.25, Preview: 0 } # provisional; the one place the display words are cut
    github: { terminal: 409, denominator: 650, ratio: 0.6292, word: "Deep" }
    slack: { terminal: 16, denominator: 17, ratio: 0.9412, word: "Deep" }
    sentry: { terminal: 78, denominator: 86, ratio: 0.9070, word: "Deep" }
    circleci: { terminal: 61, denominator: 61, ratio: 1.0000, word: "Full" }
    zendesk: { terminal: 332, denominator: 342, ratio: 0.9708, word: "Deep" }
    gitlab: { terminal: 554, denominator: 755, ratio: 0.7338, word: "Deep" }
    bitbucket: { terminal: 114, denominator: 161, ratio: 0.7081, word: "Deep" }
    ado: { terminal: 209, denominator: 232, ratio: 0.9009, word: "Deep" }
    jira: { terminal: 250, denominator: 328, ratio: 0.7622, word: "Deep" }
    linear: { terminal: 14, denominator: 17, ratio: 0.8235, word: "Deep" }
    anthropic: { terminal: 13, denominator: 13, ratio: 1.0000, word: "Full" }
    cursor: { terminal: 21, denominator: 21, ratio: 1.0000, word: "Full" }
    devin: { terminal: 113, denominator: 122, ratio: 0.9262, word: "Deep" }
    openai: { terminal: 113, denominator: 122, ratio: 0.9262, word: "Deep" }
    chatgpt: { terminal: 3, denominator: 3, ratio: 1.0000, word: "Full" }
    teams: { terminal: 13, denominator: 13, ratio: 1.0000, word: "Full" }
    pagerduty: { terminal: 211, denominator: 211, ratio: 1.0000, word: "Full" }
    salesforce: { terminal: 23, denominator: 50, ratio: 0.4600, word: "Partial" }
    hubspot: { terminal: 32, denominator: 32, ratio: 1.0000, word: "Full" }
    buildkite: { terminal: 75, denominator: 78, ratio: 0.9615, word: "Deep" }
    statuspage: { terminal: 37, denominator: 38, ratio: 0.9737, word: "Deep" }
    fleet: { terminal: 2691, denominator: 3352, ratio: 0.8028, word: "Deep" }

providers:
  github:
    rest:
      - { method: "GET", path: "/", area: "meta", tier: 1, status: "green", mode: "derive", category: "meta", subcategory: "meta" }
      - { method: "GET", path: "/advisories", area: "security-advisories", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityAdvisory", category: "security-advisories", subcategory: "global-advisories", flag: "needs-tier-review" }
      - { method: "GET", path: "/advisories/{ghsa_id}", area: "security-advisories", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityAdvisory", category: "security-advisories", subcategory: "global-advisories", flag: "needs-tier-review" }
      - { method: "GET", path: "/agents/repos/{owner}/{repo}/tasks", area: "agent-tasks", tier: 2, status: "green", mode: "derive", category: "agent-tasks", subcategory: "agent-tasks" }
      - { method: "GET", path: "/agents/repos/{owner}/{repo}/tasks/{task_id}", area: "agent-tasks", tier: 2, status: "green", mode: "derive", category: "agent-tasks", subcategory: "agent-tasks" }
      - { method: "GET", path: "/agents/tasks", area: "agent-tasks", tier: 2, status: "green", mode: "derive", category: "agent-tasks", subcategory: "agent-tasks" }
      - { method: "GET", path: "/agents/tasks/{task_id}", area: "agent-tasks", tier: 2, status: "green", mode: "derive", category: "agent-tasks", subcategory: "agent-tasks" }
      - { method: "GET", path: "/app", area: "apps", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity GitHubApp", category: "apps", subcategory: "apps", flag: "needs-tier-review" }
      - { method: "GET", path: "/app/hook/config", area: "apps", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Webhook", category: "apps", subcategory: "webhooks", flag: "needs-tier-review" }
      - { method: "GET", path: "/app/hook/deliveries", area: "apps", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Webhook", category: "apps", subcategory: "webhooks", flag: "needs-tier-review" }
      - { method: "GET", path: "/app/hook/deliveries/{delivery_id}", area: "apps", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Webhook", category: "apps", subcategory: "webhooks", flag: "needs-tier-review" }
      - { method: "GET", path: "/app/installation-requests", area: "apps", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity GitHubApp", category: "apps", subcategory: "apps", flag: "needs-tier-review" }
      - { method: "GET", path: "/app/installations", area: "apps", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity GitHubApp", category: "apps", subcategory: "apps", flag: "needs-tier-review" }
      - { method: "GET", path: "/app/installations/{installation_id}", area: "apps", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity GitHubApp", category: "apps", subcategory: "apps", flag: "needs-tier-review" }
      - { method: "GET", path: "/apps/{app_slug}", area: "apps", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity GitHubApp", category: "apps", subcategory: "apps", flag: "needs-tier-review" }
      - { method: "GET", path: "/assignments/{assignment_id}", area: "classroom", tier: 3, status: "retired", mode: "refuse", mode_reason: "GitHub Classroom is a separate product with its own teacher accounts; this universe has no classroom, and every classroom object exists only because a teacher created it — and GitHub sunset Classroom itself on 2026-08-28, so live hosts answer its own 410 while the gh pins, which all emulate the pre-sunset 2026-03-10 generation, keep this refusal (meta.retired_meaning)", mode_reviewed: "2026-09-02", category: "classroom", subcategory: "classroom", flag: "needs-tier-review" }
      - { method: "GET", path: "/assignments/{assignment_id}/accepted_assignments", area: "classroom", tier: 3, status: "retired", mode: "refuse", mode_reason: "GitHub Classroom is a separate product with its own teacher accounts; this universe has no classroom, and every classroom object exists only because a teacher created it — and GitHub sunset Classroom itself on 2026-08-28, so live hosts answer its own 410 while the gh pins, which all emulate the pre-sunset 2026-03-10 generation, keep this refusal (meta.retired_meaning)", mode_reviewed: "2026-09-02", category: "classroom", subcategory: "classroom", flag: "needs-tier-review" }
      - { method: "GET", path: "/assignments/{assignment_id}/grades", area: "classroom", tier: 3, status: "retired", mode: "refuse", mode_reason: "GitHub Classroom is a separate product with its own teacher accounts; this universe has no classroom, and every classroom object exists only because a teacher created it — and GitHub sunset Classroom itself on 2026-08-28, so live hosts answer its own 410 while the gh pins, which all emulate the pre-sunset 2026-03-10 generation, keep this refusal (meta.retired_meaning)", mode_reviewed: "2026-09-02", category: "classroom", subcategory: "classroom", flag: "needs-tier-review" }
      - { method: "GET", path: "/classrooms", area: "classroom", tier: 3, status: "retired", mode: "refuse", mode_reason: "GitHub Classroom is a separate product with its own teacher accounts; this universe has no classroom, and every classroom object exists only because a teacher created it — and GitHub sunset Classroom itself on 2026-08-28, so live hosts answer its own 410 while the gh pins, which all emulate the pre-sunset 2026-03-10 generation, keep this refusal (meta.retired_meaning)", mode_reviewed: "2026-09-02", category: "classroom", subcategory: "classroom", flag: "needs-tier-review" }
      - { method: "GET", path: "/classrooms/{classroom_id}", area: "classroom", tier: 3, status: "retired", mode: "refuse", mode_reason: "GitHub Classroom is a separate product with its own teacher accounts; this universe has no classroom, and every classroom object exists only because a teacher created it — and GitHub sunset Classroom itself on 2026-08-28, so live hosts answer its own 410 while the gh pins, which all emulate the pre-sunset 2026-03-10 generation, keep this refusal (meta.retired_meaning)", mode_reviewed: "2026-09-02", category: "classroom", subcategory: "classroom", flag: "needs-tier-review" }
      - { method: "GET", path: "/classrooms/{classroom_id}/assignments", area: "classroom", tier: 3, status: "retired", mode: "refuse", mode_reason: "GitHub Classroom is a separate product with its own teacher accounts; this universe has no classroom, and every classroom object exists only because a teacher created it — and GitHub sunset Classroom itself on 2026-08-28, so live hosts answer its own 410 while the gh pins, which all emulate the pre-sunset 2026-03-10 generation, keep this refusal (meta.retired_meaning)", mode_reviewed: "2026-09-02", category: "classroom", subcategory: "classroom", flag: "needs-tier-review" }
      - { method: "GET", path: "/codes_of_conduct", area: "codes-of-conduct", tier: 3, status: "deferred", mode: "generate", mode_reason: "static provider catalog, and NOT `derive`: `derive` is defined in this file as computed from artifact rows that already exist, and a vendor catalog is not an artifact row. LICENCE: NO USABLE GRANT, and the CC BY 4.0 premise is out of date — EthicalSource/contributor_covenant's only LICENSE.md is the Hippocratic License 3.0, and the other body GitHub serves is the Django Code of Conduct, CC BY-SA 4.0, whose ShareAlike reciprocity cannot travel into a compiled artifact this service publishes. The per-item licence finding is coverage/reviews/2026-09-09-hello-15-stale-reasons-git-hosts.md §5.3, and §5.4 records why the label waited for a shard arm", mode_reviewed: "2026-09-09", held: "data-licensing", held_reviewed: "2026-09-09", category: "codes-of-conduct", subcategory: "codes-of-conduct", flag: "needs-tier-review" }
      - { method: "GET", path: "/codes_of_conduct/{key}", area: "codes-of-conduct", tier: 3, status: "deferred", mode: "generate", mode_reason: "static provider catalog, and NOT `derive`: `derive` is defined in this file as computed from artifact rows that already exist, and a vendor catalog is not an artifact row. LICENCE: NO USABLE GRANT, and the CC BY 4.0 premise is out of date — EthicalSource/contributor_covenant's only LICENSE.md is the Hippocratic License 3.0, and the other body GitHub serves is the Django Code of Conduct, CC BY-SA 4.0, whose ShareAlike reciprocity cannot travel into a compiled artifact this service publishes. The per-item licence finding is coverage/reviews/2026-09-09-hello-15-stale-reasons-git-hosts.md §5.3, and §5.4 records why the label waited for a shard arm", mode_reviewed: "2026-09-09", held: "data-licensing", held_reviewed: "2026-09-09", category: "codes-of-conduct", subcategory: "codes-of-conduct", flag: "needs-tier-review" }
      - { method: "GET", path: "/emojis", area: "emojis", tier: 3, status: "deferred", mode: "generate", mode_reason: "static provider catalog, and NOT `derive`: `derive` is defined in this file as computed from artifact rows that already exist, and a vendor catalog is not an artifact row. LICENCE: NO GRANT — the response is a map of roughly 1,870 shortcodes whose VALUES are github.githubassets.com URLs for GitHub's own image assets, which this project holds no grant to redistribute and which would also hand a caller live github.com URLs from a sandbox host. The per-item licence finding is coverage/reviews/2026-09-09-hello-15-stale-reasons-git-hosts.md §5.3, and §5.4 records why the label waited for a shard arm", mode_reviewed: "2026-09-09", held: "data-licensing", held_reviewed: "2026-09-09", category: "emojis", subcategory: "emojis", flag: "needs-tier-review" }
      - { method: "GET", path: "/enterprises/{enterprise}/actions/cache/retention-limit", area: "actions", tier: 2, status: "deferred", mode: "refuse", mode_reason: "olympus-labs is a standalone organization, not an enterprise account, so no enterprise slug in this universe resolves — GitHub's own 404 for an unknown enterprise is the whole answer", mode_reviewed: "2026-09-01", category: "actions", subcategory: "cache" }
      - { method: "GET", path: "/enterprises/{enterprise}/actions/cache/storage-limit", area: "actions", tier: 2, status: "deferred", mode: "refuse", mode_reason: "olympus-labs is a standalone organization, not an enterprise account, so no enterprise slug in this universe resolves — GitHub's own 404 for an unknown enterprise is the whole answer", mode_reviewed: "2026-09-01", category: "actions", subcategory: "cache" }
      - { method: "GET", path: "/enterprises/{enterprise}/actions/oidc/customization/properties/repo", area: "actions", tier: 2, status: "deferred", mode: "refuse", mode_reason: "olympus-labs is a standalone organization, not an enterprise account, so no enterprise slug in this universe resolves — GitHub's own 404 for an unknown enterprise is the whole answer", mode_reviewed: "2026-09-01", category: "actions", subcategory: "oidc" }
      - { method: "GET", path: "/enterprises/{enterprise}/code-security/configurations", area: "code-security", tier: 3, status: "deferred", mode: "refuse", mode_reason: "olympus-labs is a standalone organization, not an enterprise account, so no enterprise slug in this universe resolves — GitHub's own 404 for an unknown enterprise is the whole answer", mode_reviewed: "2026-09-01", category: "code-security", subcategory: "configurations", flag: "needs-tier-review" }
      - { method: "GET", path: "/enterprises/{enterprise}/code-security/configurations/{configuration_id}", area: "code-security", tier: 3, status: "deferred", mode: "refuse", mode_reason: "olympus-labs is a standalone organization, not an enterprise account, so no enterprise slug in this universe resolves — GitHub's own 404 for an unknown enterprise is the whole answer", mode_reviewed: "2026-09-01", category: "code-security", subcategory: "configurations", flag: "needs-tier-review" }
      - { method: "GET", path: "/enterprises/{enterprise}/code-security/configurations/{configuration_id}/repositories", area: "code-security", tier: 3, status: "deferred", mode: "refuse", mode_reason: "olympus-labs is a standalone organization, not an enterprise account, so no enterprise slug in this universe resolves — GitHub's own 404 for an unknown enterprise is the whole answer", mode_reviewed: "2026-09-01", category: "code-security", subcategory: "configurations", flag: "needs-tier-review" }
      - { method: "GET", path: "/enterprises/{enterprise}/code-security/configurations/defaults", area: "code-security", tier: 3, status: "deferred", mode: "refuse", mode_reason: "olympus-labs is a standalone organization, not an enterprise account, so no enterprise slug in this universe resolves — GitHub's own 404 for an unknown enterprise is the whole answer", mode_reviewed: "2026-09-01", category: "code-security", subcategory: "configurations", flag: "needs-tier-review" }
      - { method: "GET", path: "/enterprises/{enterprise}/copilot/metrics/reports/enterprise-1-day", area: "copilot", tier: 2, status: "deferred", mode: "refuse", mode_reason: "olympus-labs is a standalone organization, not an enterprise account, so no enterprise slug in this universe resolves — GitHub's own 404 for an unknown enterprise is the whole answer. The identical ruling already governs every sibling under this prefix (see `github|rest|GET|/enterprises/{enterprise}/teams`, reviewed 2026-09-01); serving a Copilot report here would require minting the enterprise those fifteen rows deny. RULED by the founder 2026-09-09", mode_reviewed: "2026-09-09", category: "copilot", subcategory: "copilot-usage-metrics" }
      - { method: "GET", path: "/enterprises/{enterprise}/copilot/metrics/reports/enterprise-28-day/latest", area: "copilot", tier: 2, status: "deferred", mode: "refuse", mode_reason: "olympus-labs is a standalone organization, not an enterprise account, so no enterprise slug in this universe resolves — GitHub's own 404 for an unknown enterprise is the whole answer. The identical ruling already governs every sibling under this prefix (see `github|rest|GET|/enterprises/{enterprise}/teams`, reviewed 2026-09-01); serving a Copilot report here would require minting the enterprise those fifteen rows deny. RULED by the founder 2026-09-09", mode_reviewed: "2026-09-09", category: "copilot", subcategory: "copilot-usage-metrics" }
      - { method: "GET", path: "/enterprises/{enterprise}/copilot/metrics/reports/repos-1-day", area: "copilot", tier: 2, status: "deferred", mode: "refuse", mode_reason: "olympus-labs is a standalone organization, not an enterprise account, so no enterprise slug in this universe resolves — GitHub's own 404 for an unknown enterprise is the whole answer. The identical ruling already governs every sibling under this prefix (see `github|rest|GET|/enterprises/{enterprise}/teams`, reviewed 2026-09-01); serving a Copilot report here would require minting the enterprise those fifteen rows deny. RULED by the founder 2026-09-09", mode_reviewed: "2026-09-09", category: "copilot", subcategory: "copilot-usage-metrics" }
      - { method: "GET", path: "/enterprises/{enterprise}/copilot/metrics/reports/user-teams-1-day", area: "copilot", tier: 2, status: "deferred", mode: "refuse", mode_reason: "olympus-labs is a standalone organization, not an enterprise account, so no enterprise slug in this universe resolves — GitHub's own 404 for an unknown enterprise is the whole answer. The identical ruling already governs every sibling under this prefix (see `github|rest|GET|/enterprises/{enterprise}/teams`, reviewed 2026-09-01); serving a Copilot report here would require minting the enterprise those fifteen rows deny. RULED by the founder 2026-09-09", mode_reviewed: "2026-09-09", category: "copilot", subcategory: "copilot-usage-metrics" }
      - { method: "GET", path: "/enterprises/{enterprise}/copilot/metrics/reports/users-1-day", area: "copilot", tier: 2, status: "deferred", mode: "refuse", mode_reason: "olympus-labs is a standalone organization, not an enterprise account, so no enterprise slug in this universe resolves — GitHub's own 404 for an unknown enterprise is the whole answer. The identical ruling already governs every sibling under this prefix (see `github|rest|GET|/enterprises/{enterprise}/teams`, reviewed 2026-09-01); serving a Copilot report here would require minting the enterprise those fifteen rows deny. RULED by the founder 2026-09-09", mode_reviewed: "2026-09-09", category: "copilot", subcategory: "copilot-usage-metrics" }
      - { method: "GET", path: "/enterprises/{enterprise}/copilot/metrics/reports/users-28-day/latest", area: "copilot", tier: 2, status: "deferred", mode: "refuse", mode_reason: "olympus-labs is a standalone organization, not an enterprise account, so no enterprise slug in this universe resolves — GitHub's own 404 for an unknown enterprise is the whole answer. The identical ruling already governs every sibling under this prefix (see `github|rest|GET|/enterprises/{enterprise}/teams`, reviewed 2026-09-01); serving a Copilot report here would require minting the enterprise those fifteen rows deny. RULED by the founder 2026-09-09", mode_reviewed: "2026-09-09", category: "copilot", subcategory: "copilot-usage-metrics" }
      - { method: "GET", path: "/enterprises/{enterprise}/dependabot/alerts", area: "dependabot", tier: 3, status: "deferred", mode: "refuse", mode_reason: "olympus-labs is a standalone organization, not an enterprise account, so no enterprise slug in this universe resolves — GitHub's own 404 for an unknown enterprise is the whole answer", mode_reviewed: "2026-09-01", category: "dependabot", subcategory: "alerts" }
      - { method: "GET", path: "/enterprises/{enterprise}/dependabot/repository-access", area: "dependabot", tier: 3, status: "deferred", mode: "refuse", mode_reason: "olympus-labs is a standalone organization, not an enterprise account, so no enterprise slug in this universe resolves — GitHub's own 404 for an unknown enterprise is the whole answer", mode_reviewed: "2026-09-01", category: "dependabot", subcategory: "repository-access" }
      - { method: "GET", path: "/enterprises/{enterprise}/teams", area: "enterprise-teams", tier: 3, status: "deferred", mode: "refuse", mode_reason: "olympus-labs is a standalone organization, not an enterprise account, so no enterprise slug in this universe resolves — GitHub's own 404 for an unknown enterprise is the whole answer", mode_reviewed: "2026-09-01", category: "enterprise-teams", subcategory: "enterprise-teams", flag: "needs-tier-review" }
      - { method: "GET", path: "/enterprises/{enterprise}/teams/{enterprise-team}/memberships", area: "enterprise-teams", tier: 3, status: "deferred", mode: "refuse", mode_reason: "olympus-labs is a standalone organization, not an enterprise account, so no enterprise slug in this universe resolves — GitHub's own 404 for an unknown enterprise is the whole answer", mode_reviewed: "2026-09-01", category: "enterprise-teams", subcategory: "enterprise-team-members", flag: "needs-tier-review" }
      - { method: "GET", path: "/enterprises/{enterprise}/teams/{enterprise-team}/memberships/{username}", area: "enterprise-teams", tier: 3, status: "deferred", mode: "refuse", mode_reason: "olympus-labs is a standalone organization, not an enterprise account, so no enterprise slug in this universe resolves — GitHub's own 404 for an unknown enterprise is the whole answer", mode_reviewed: "2026-09-01", category: "enterprise-teams", subcategory: "enterprise-team-members", flag: "needs-tier-review" }
      - { method: "GET", path: "/enterprises/{enterprise}/teams/{enterprise-team}/organizations", area: "enterprise-teams", tier: 3, status: "deferred", mode: "refuse", mode_reason: "olympus-labs is a standalone organization, not an enterprise account, so no enterprise slug in this universe resolves — GitHub's own 404 for an unknown enterprise is the whole answer", mode_reviewed: "2026-09-01", category: "enterprise-teams", subcategory: "enterprise-team-organizations", flag: "needs-tier-review" }
      - { method: "GET", path: "/enterprises/{enterprise}/teams/{enterprise-team}/organizations/{org}", area: "enterprise-teams", tier: 3, status: "deferred", mode: "refuse", mode_reason: "olympus-labs is a standalone organization, not an enterprise account, so no enterprise slug in this universe resolves — GitHub's own 404 for an unknown enterprise is the whole answer", mode_reviewed: "2026-09-01", category: "enterprise-teams", subcategory: "enterprise-team-organizations", flag: "needs-tier-review" }
      - { method: "GET", path: "/enterprises/{enterprise}/teams/{team_slug}", area: "enterprise-teams", tier: 3, status: "deferred", mode: "refuse", mode_reason: "olympus-labs is a standalone organization, not an enterprise account, so no enterprise slug in this universe resolves — GitHub's own 404 for an unknown enterprise is the whole answer", mode_reviewed: "2026-09-01", category: "enterprise-teams", subcategory: "enterprise-teams", flag: "needs-tier-review" }
      - { method: "GET", path: "/events", area: "events-timeline", tier: 2, status: "green", mode: "derive", category: "activity", subcategory: "events" }
      - { method: "GET", path: "/feeds", area: "activity", tier: 3, status: "green", mode: "derive", mode_reason: "the feed document is a set of URLs computed from the authenticated persona and the repos they can see", category: "activity", subcategory: "feeds", flag: "needs-tier-review" }
      - { method: "GET", path: "/gists", area: "gists", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Gist", category: "gists", subcategory: "gists" }
      - { method: "GET", path: "/gists/{gist_id}", area: "gists", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Gist", category: "gists", subcategory: "gists" }
      - { method: "GET", path: "/gists/{gist_id}/{sha}", area: "gists", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Gist", category: "gists", subcategory: "gists" }
      - { method: "GET", path: "/gists/{gist_id}/comments", area: "gists", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Gist", category: "gists", subcategory: "comments" }
      - { method: "GET", path: "/gists/{gist_id}/comments/{comment_id}", area: "gists", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Gist", category: "gists", subcategory: "comments" }
      - { method: "GET", path: "/gists/{gist_id}/commits", area: "gists", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Gist", category: "gists", subcategory: "gists" }
      - { method: "GET", path: "/gists/{gist_id}/forks", area: "gists", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Gist", category: "gists", subcategory: "gists" }
      - { method: "GET", path: "/gists/{gist_id}/star", area: "gists", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Gist", category: "gists", subcategory: "gists" }
      - { method: "GET", path: "/gists/public", area: "gists", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Gist", category: "gists", subcategory: "gists" }
      - { method: "GET", path: "/gists/starred", area: "gists", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Gist", category: "gists", subcategory: "gists" }
      - { method: "GET", path: "/gitignore/templates", area: "gitignore", tier: 3, status: "green", mode: "derive", mode_reason: "reader.listGitignoreTemplates() reads gitignore_template; every one of the 163 names it lists resolves at {name}, which conformance follows one by one. licence: CC0-1.0 — github/gitignore publishes its templates under the Creative Commons Zero v1.0 Universal public-domain dedication (its own LICENSE file; gh api repos/github/gitignore/license returns spdx_id CC0-1.0). Older pins answer the refCatalogs generation-gap 404 rather than an empty catalogue, which on these rows would be a false claim about the HOST. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", category: "gitignore", subcategory: "gitignore", flag: "needs-tier-review" }
      - { method: "GET", path: "/gitignore/templates/{name}", area: "gitignore", tier: 3, status: "green", mode: "derive", mode_reason: "reader.gitignoreTemplate(name) reads gitignore_template and serves the file's bytes verbatim; the lookup is case-sensitive, as upstream's own file names are. licence: CC0-1.0 — github/gitignore publishes its templates under the Creative Commons Zero v1.0 Universal public-domain dedication (its own LICENSE file; gh api repos/github/gitignore/license returns spdx_id CC0-1.0). Older pins answer the refCatalogs generation-gap 404 rather than an empty catalogue, which on these rows would be a false claim about the HOST. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", category: "gitignore", subcategory: "gitignore", flag: "needs-tier-review" }
      - { method: "GET", path: "/installation/repositories", area: "apps", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity GitHubApp", category: "apps", subcategory: "installations", flag: "needs-tier-review" }
      - { method: "GET", path: "/issues", area: "issues", tier: 1, status: "green", mode: "derive", mode_reason: "issue lists across the repo, org and authenticated persona", category: "issues", subcategory: "issues" }
      - { method: "GET", path: "/licenses", area: "licenses", tier: 3, status: "green", mode: "derive", mode_reason: "reader.listLicenses() reads license_catalog (a compile-time table, never a renderer constant) and render-catalogs.ts shapes license-simple over it; node_id is minted with artifact's own nodeId(\"License\", key) except mit, whose api.github.com value the repository object has published since Wave A. licence: FREE — the thirteen bodies GitHub serves (gh api /licenses: agpl-3.0, apache-2.0, bsd-2-clause, bsd-3-clause, bsl-1.0, cc0-1.0, epl-2.0, gpl-2.0, gpl-3.0, lgpl-2.1, mit, mpl-2.0, unlicense) are meant for verbatim redistribution and several say so in their own header — the GPL family carries \"Everyone is permitted to copy and distribute verbatim copies of this license document\", CC0-1.0 and Unlicense are public-domain dedications, Apache-2.0 ships an APPENDIX instructing reproduction; the key/spdx_id/permissions metadata comes from github/choosealicense.com, which is MIT (gh api repos/github/choosealicense.com/license). Older pins answer the refCatalogs generation-gap 404 rather than an empty catalogue, which on these rows would be a false claim about the HOST. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", category: "licenses", subcategory: "licenses", flag: "needs-tier-review" }
      - { method: "GET", path: "/licenses/{license}", area: "licenses", tier: 3, status: "green", mode: "derive", mode_reason: "reader.license(key) reads license_catalog and render-catalogs.ts shapes the full license component; the body is the artifact's body column byte for byte, upstream's [year]/[fullname] placeholders included. licence: FREE — the thirteen bodies GitHub serves (gh api /licenses: agpl-3.0, apache-2.0, bsd-2-clause, bsd-3-clause, bsl-1.0, cc0-1.0, epl-2.0, gpl-2.0, gpl-3.0, lgpl-2.1, mit, mpl-2.0, unlicense) are meant for verbatim redistribution and several say so in their own header — the GPL family carries \"Everyone is permitted to copy and distribute verbatim copies of this license document\", CC0-1.0 and Unlicense are public-domain dedications, Apache-2.0 ships an APPENDIX instructing reproduction; the key/spdx_id/permissions metadata comes from github/choosealicense.com, which is MIT (gh api repos/github/choosealicense.com/license). Older pins answer the refCatalogs generation-gap 404 rather than an empty catalogue, which on these rows would be a false claim about the HOST. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", category: "licenses", subcategory: "licenses", flag: "needs-tier-review" }
      - { method: "GET", path: "/marketplace_listing/accounts/{account_id}", area: "apps", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the org is neither a GitHub Marketplace listing nor a purchaser, and GitHub answers 404 to marketplace reads for an account with no listing", mode_reviewed: "2026-09-01", category: "apps", subcategory: "marketplace", flag: "needs-tier-review" }
      - { method: "GET", path: "/marketplace_listing/plans", area: "apps", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the org is neither a GitHub Marketplace listing nor a purchaser, and GitHub answers 404 to marketplace reads for an account with no listing", mode_reviewed: "2026-09-01", category: "apps", subcategory: "marketplace", flag: "needs-tier-review" }
      - { method: "GET", path: "/marketplace_listing/plans/{plan_id}/accounts", area: "apps", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the org is neither a GitHub Marketplace listing nor a purchaser, and GitHub answers 404 to marketplace reads for an account with no listing", mode_reviewed: "2026-09-01", category: "apps", subcategory: "marketplace", flag: "needs-tier-review" }
      - { method: "GET", path: "/marketplace_listing/stubbed/accounts/{account_id}", area: "apps", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the org is neither a GitHub Marketplace listing nor a purchaser, and GitHub answers 404 to marketplace reads for an account with no listing", mode_reviewed: "2026-09-01", category: "apps", subcategory: "marketplace", flag: "needs-tier-review" }
      - { method: "GET", path: "/marketplace_listing/stubbed/plans", area: "apps", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the org is neither a GitHub Marketplace listing nor a purchaser, and GitHub answers 404 to marketplace reads for an account with no listing", mode_reviewed: "2026-09-01", category: "apps", subcategory: "marketplace", flag: "needs-tier-review" }
      - { method: "GET", path: "/marketplace_listing/stubbed/plans/{plan_id}/accounts", area: "apps", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the org is neither a GitHub Marketplace listing nor a purchaser, and GitHub answers 404 to marketplace reads for an account with no listing", mode_reviewed: "2026-09-01", category: "apps", subcategory: "marketplace", flag: "needs-tier-review" }
      - { method: "GET", path: "/meta", area: "meta", tier: 1, status: "green", mode: "derive", category: "meta", subcategory: "meta" }
      - { method: "GET", path: "/networks/{owner}/{repo}/events", area: "events-timeline", tier: 2, status: "green", mode: "derive", category: "activity", subcategory: "events" }
      - { method: "GET", path: "/notifications", area: "notifications", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Notification", category: "activity", subcategory: "notifications" }
      - { method: "GET", path: "/notifications/threads/{thread_id}", area: "notifications", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Notification", category: "activity", subcategory: "notifications" }
      - { method: "GET", path: "/notifications/threads/{thread_id}/subscription", area: "notifications", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Notification", category: "activity", subcategory: "notifications" }
      - { method: "GET", path: "/octocat", area: "meta", tier: 1, status: "planned", mode: "generate", mode_reason: "static provider catalog, and NOT `derive`: `derive` is defined in this file as computed from artifact rows that already exist, and a vendor catalog is not an artifact row. LICENCE: NO GRANT — the response is ASCII art of the Octocat, which is GitHub artwork and a GitHub trademark. The per-item licence finding is coverage/reviews/2026-09-09-hello-15-stale-reasons-git-hosts.md §5.3, and §5.4 records why the label waited for a shard arm", mode_reviewed: "2026-09-09", held: "data-licensing", held_reviewed: "2026-09-09", category: "meta", subcategory: "meta" }
      - { method: "GET", path: "/organizations", area: "orgs", tier: 1, status: "green", mode: "derive", mode_reason: "the org list is the one org this universe carries", category: "orgs", subcategory: "orgs" }
      - { method: "GET", path: "/organizations/{org}/actions/cache/retention-limit", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsCache", category: "actions", subcategory: "cache" }
      - { method: "GET", path: "/organizations/{org}/actions/cache/storage-limit", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsCache", category: "actions", subcategory: "cache" }
      - { method: "GET", path: "/organizations/{org}/settings/billing/ai_credit/usage", area: "billing-admin-enterprise", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity BillingPeriod", category: "billing", subcategory: "usage", flag: "needs-tier-review" }
      - { method: "GET", path: "/organizations/{org}/settings/billing/budgets", area: "billing-admin-enterprise", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Subscription", category: "billing", subcategory: "budgets", flag: "needs-tier-review" }
      - { method: "GET", path: "/organizations/{org}/settings/billing/budgets/{budget_id}", area: "billing-admin-enterprise", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Subscription", category: "billing", subcategory: "budgets", flag: "needs-tier-review" }
      - { method: "GET", path: "/organizations/{org}/settings/billing/premium_request/usage", area: "billing-admin-enterprise", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity BillingPeriod", category: "billing", subcategory: "usage", flag: "needs-tier-review" }
      - { method: "GET", path: "/organizations/{org}/settings/billing/usage", area: "billing-admin-enterprise", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity BillingPeriod", category: "billing", subcategory: "usage", flag: "needs-tier-review" }
      - { method: "GET", path: "/organizations/{org}/settings/billing/usage/summary", area: "billing-admin-enterprise", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity BillingPeriod", category: "billing", subcategory: "usage", flag: "needs-tier-review" }
      - { method: "GET", path: "/orgs/{org}", area: "orgs", tier: 1, status: "green", mode: "derive", category: "orgs", subcategory: "orgs" }
      - { method: "GET", path: "/orgs/{org}/actions/cache/usage", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsCache", category: "actions", subcategory: "cache" }
      - { method: "GET", path: "/orgs/{org}/actions/cache/usage-by-repository", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsCache", category: "actions", subcategory: "cache" }
      - { method: "GET", path: "/orgs/{org}/actions/hosted-runners", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity HostedRunner", category: "actions", subcategory: "hosted-runners" }
      - { method: "GET", path: "/orgs/{org}/actions/hosted-runners/{hosted_runner_id}", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity HostedRunner", category: "actions", subcategory: "hosted-runners" }
      - { method: "GET", path: "/orgs/{org}/actions/hosted-runners/images/custom", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity HostedRunner", category: "actions", subcategory: "hosted-runners" }
      - { method: "GET", path: "/orgs/{org}/actions/hosted-runners/images/custom/{image_definition_id}", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity HostedRunner", category: "actions", subcategory: "hosted-runners" }
      - { method: "GET", path: "/orgs/{org}/actions/hosted-runners/images/custom/{image_definition_id}/versions", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity HostedRunner", category: "actions", subcategory: "hosted-runners" }
      - { method: "GET", path: "/orgs/{org}/actions/hosted-runners/images/custom/{image_definition_id}/versions/{version}", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity HostedRunner", category: "actions", subcategory: "hosted-runners" }
      - { method: "GET", path: "/orgs/{org}/actions/hosted-runners/images/github-owned", area: "actions", tier: 2, status: "green", mode: "derive", mode_reason: "reader.refCatalog(\"github.runner-images-github-owned\"); every row carries source: github and none of them is on the partner catalogue. licence: FACTUAL — the ids are operating-system distribution names and versions (\"ubuntu-20.04\" on platform \"linux-x64\" in actions-hosted-runner-curated-image), which carry no authorship. Older pins answer the refCatalogs generation-gap 404 rather than an empty catalogue, which on these rows would be a false claim about the HOST. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", category: "actions", subcategory: "hosted-runners" }
      - { method: "GET", path: "/orgs/{org}/actions/hosted-runners/images/partner", area: "actions", tier: 2, status: "green", mode: "derive", mode_reason: "reader.refCatalog(\"github.runner-images-partner\") - the one catalogue in this domain with a theme leg, since source: partner names third-party vendors. licence: NO GRANT NEEDED — source: \"partner\" names third-party vendors, which is exactly the objection the /vendors ruling met, and it settled it by making the catalogue FICTIONAL. No vendor's data is copied, so nothing has to be licensed. Older pins answer the refCatalogs generation-gap 404 rather than an empty catalogue, which on these rows would be a false claim about the HOST. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", category: "actions", subcategory: "hosted-runners" }
      - { method: "GET", path: "/orgs/{org}/actions/hosted-runners/limits", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity HostedRunner", category: "actions", subcategory: "hosted-runners" }
      - { method: "GET", path: "/orgs/{org}/actions/hosted-runners/machine-sizes", area: "actions", tier: 2, status: "green", mode: "derive", mode_reason: "reader.refCatalog(\"github.runner-machine-sizes\") in ord order (smallest first, which key order would reverse). licence: FACTUAL — the response is hardware numbers ({id: \"8-core\", cpu_cores, memory_gb, storage_gb} in actions-hosted-runner-machine-spec), which carry no authorship. Older pins answer the refCatalogs generation-gap 404 rather than an empty catalogue, which on these rows would be a false claim about the HOST. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", category: "actions", subcategory: "hosted-runners" }
      - { method: "GET", path: "/orgs/{org}/actions/hosted-runners/platforms", area: "actions", tier: 2, status: "green", mode: "derive", mode_reason: "reader.refCatalog(\"github.runner-platforms\"); every platform an image names is asserted to be one this list offers. licence: FACTUAL — the response is an enumeration of operating-system/architecture identifiers (\"linux-x64\", \"win-x64\" in the vendored description's own example), which carries no authorship. Older pins answer the refCatalogs generation-gap 404 rather than an empty catalogue, which on these rows would be a false claim about the HOST. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", category: "actions", subcategory: "hosted-runners" }
      - { method: "GET", path: "/orgs/{org}/actions/oidc/customization/properties/repo", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsPolicy", category: "actions", subcategory: "oidc" }
      - { method: "GET", path: "/orgs/{org}/actions/oidc/customization/sub", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsPolicy", category: "actions", subcategory: "oidc" }
      - { method: "GET", path: "/orgs/{org}/actions/permissions", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsPolicy", category: "actions", subcategory: "permissions" }
      - { method: "GET", path: "/orgs/{org}/actions/permissions/artifact-and-log-retention", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsPolicy", category: "actions", subcategory: "permissions" }
      - { method: "GET", path: "/orgs/{org}/actions/permissions/fork-pr-contributor-approval", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsPolicy", category: "actions", subcategory: "permissions" }
      - { method: "GET", path: "/orgs/{org}/actions/permissions/fork-pr-workflows-private-repos", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsPolicy", category: "actions", subcategory: "permissions" }
      - { method: "GET", path: "/orgs/{org}/actions/permissions/repositories", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsPolicy", category: "actions", subcategory: "permissions" }
      - { method: "GET", path: "/orgs/{org}/actions/permissions/selected-actions", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsPolicy", category: "actions", subcategory: "permissions" }
      - { method: "GET", path: "/orgs/{org}/actions/permissions/self-hosted-runners", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsPolicy", category: "actions", subcategory: "permissions" }
      - { method: "GET", path: "/orgs/{org}/actions/permissions/self-hosted-runners/repositories", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsPolicy", category: "actions", subcategory: "permissions" }
      - { method: "GET", path: "/orgs/{org}/actions/permissions/workflow", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsPolicy", category: "actions", subcategory: "permissions" }
      - { method: "GET", path: "/orgs/{org}/actions/runner-groups", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Runner", category: "actions", subcategory: "self-hosted-runner-groups" }
      - { method: "GET", path: "/orgs/{org}/actions/runner-groups/{runner_group_id}", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Runner", category: "actions", subcategory: "self-hosted-runner-groups" }
      - { method: "GET", path: "/orgs/{org}/actions/runner-groups/{runner_group_id}/hosted-runners", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Runner", category: "actions", subcategory: "self-hosted-runner-groups" }
      - { method: "GET", path: "/orgs/{org}/actions/runner-groups/{runner_group_id}/repositories", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Runner", category: "actions", subcategory: "self-hosted-runner-groups" }
      - { method: "GET", path: "/orgs/{org}/actions/runner-groups/{runner_group_id}/runners", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Runner", category: "actions", subcategory: "self-hosted-runner-groups" }
      - { method: "GET", path: "/orgs/{org}/actions/runners", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Runner", category: "actions", subcategory: "self-hosted-runners" }
      - { method: "GET", path: "/orgs/{org}/actions/runners/{runner_id}", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Runner", category: "actions", subcategory: "self-hosted-runners" }
      - { method: "GET", path: "/orgs/{org}/actions/runners/{runner_id}/labels", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Runner", category: "actions", subcategory: "self-hosted-runners" }
      - { method: "GET", path: "/orgs/{org}/actions/runners/downloads", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Runner", category: "actions", subcategory: "self-hosted-runners" }
      - { method: "GET", path: "/orgs/{org}/actions/secrets", area: "actions", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` + `ci_binding_scope` - the settings and credentials this organization hands its pipelines. GitHub publishes ONE object as two URL families, so a secret is a binding whose value may not be published and a variable is one whose value may; canon carries exactly that boolean (`masked`) and this row is the same read with a different filter. The `actions` family is canon's `pipeline` audience; served as `organization-actions-secret`, so `visibility` is published and `selected_repositories_url` only on a `selected` row - a link on an `all` row would advertise a route that answers 409. NO `value` MEMBER IS SERVED AND NONE EXISTS: `actions-secret` declares a name and two dates, `ci_binding.value` is NULL on every masked row, and conformance asserts the property is absent from every served secret rather than trusting the schema, which sets no `additionalProperties: false`", mode_reviewed: "2026-09-12", category: "actions", subcategory: "secrets" }
      - { method: "GET", path: "/orgs/{org}/actions/secrets/{secret_name}", area: "actions", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` + `ci_binding_scope` - the settings and credentials this organization hands its pipelines. GitHub publishes ONE object as two URL families, so a secret is a binding whose value may not be published and a variable is one whose value may; canon carries exactly that boolean (`masked`) and this row is the same read with a different filter. The `actions` family is canon's `pipeline` audience; a name the list published, never a name recomputed from the theme's pool. A name this organization does not hold is GitHub's own 404", mode_reviewed: "2026-09-12", category: "actions", subcategory: "secrets" }
      - { method: "GET", path: "/orgs/{org}/actions/secrets/{secret_name}/repositories", area: "actions", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` + `ci_binding_scope` - the settings and credentials this organization hands its pipelines. GitHub publishes ONE object as two URL families, so a secret is a binding whose value may not be published and a variable is one whose value may; canon carries exactly that boolean (`masked`) and this row is the same read with a different filter. The `actions` family is canon's `pipeline` audience; the repositories the secret actually reaches - `all` reaches every one, `private` the private ones, `selected` the named ones. The vendored operation declares NO 409 on the secret form (only the variable form does), so this answers the 200 whatever the visibility, and conformance fetches every repository it names to prove the link resolves", mode_reviewed: "2026-09-12", category: "actions", subcategory: "secrets" }
      - { method: "GET", path: "/orgs/{org}/actions/secrets/public-key", area: "actions", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` + `ci_binding_scope` - the settings and credentials this organization hands its pipelines. GitHub publishes ONE object as two URL families, so a secret is a binding whose value may not be published and a variable is one whose value may; canon carries exactly that boolean (`masked`) and this row is the same read with a different filter. The `actions` family is canon's `pipeline` audience; the scope's own 32 X25519 public-key bytes, base64-encoded, and its monotonic `key_id`. THE PUBLIC HALF IS REAL AND THERE IS NO PRIVATE HALF - this universe accepts no writes, so nothing is ever encrypted to these bytes; conformance base64-decodes them and asserts the length is 32 rather than accepting any string", mode_reviewed: "2026-09-12", category: "actions", subcategory: "secrets" }
      - { method: "GET", path: "/orgs/{org}/actions/variables", area: "actions", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` + `ci_binding_scope` - the settings and credentials this organization hands its pipelines. GitHub publishes ONE object as two URL families, so a secret is a binding whose value may not be published and a variable is one whose value may; canon carries exactly that boolean (`masked`) and this row is the same read with a different filter. The `actions` family is canon's `pipeline` audience; `organization-actions-variable`, whose `value` IS declared and is READ from the artifact row canon's `value_source` names - the telemetry exporter's endpoint and its protocol - so the setting and the thing it configures cannot drift apart", mode_reviewed: "2026-09-12", category: "actions", subcategory: "variables" }
      - { method: "GET", path: "/orgs/{org}/actions/variables/{name}", area: "actions", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` + `ci_binding_scope` - the settings and credentials this organization hands its pipelines. GitHub publishes ONE object as two URL families, so a secret is a binding whose value may not be published and a variable is one whose value may; canon carries exactly that boolean (`masked`) and this row is the same read with a different filter. The `actions` family is canon's `pipeline` audience; a name the list published. A name this organization does not hold is GitHub's own 404", mode_reviewed: "2026-09-12", category: "actions", subcategory: "variables" }
      - { method: "GET", path: "/orgs/{org}/actions/variables/{name}/repositories", area: "actions", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` + `ci_binding_scope` - the settings and credentials this organization hands its pipelines. GitHub publishes ONE object as two URL families, so a secret is a binding whose value may not be published and a variable is one whose value may; canon carries exactly that boolean (`masked`) and this row is the same read with a different filter. The vendored operation declares a 200 AND a body-less 409 - \"Response when the visibility of the variable is not set to `selected`\" - and BOTH branches have a row in this universe, which is the vendored document specifying what the organization has to look like. This one answers the 200: the organization's OTLP protocol variable is `selected` to the repository whose collector agent is configured for that wire format. The `agents` twin answers the 409", mode_reviewed: "2026-09-12", category: "actions", subcategory: "variables" }
      - { method: "GET", path: "/orgs/{org}/agents/secrets", area: "agents", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` + `ci_binding_scope` - the settings and credentials this organization hands its pipelines. GitHub publishes ONE object as two URL families, so a secret is a binding whose value may not be published and a variable is one whose value may; canon carries exactly that boolean (`masked`) and this row is the same read with a different filter. The `agents` family is canon's `coding-agent` audience - GitHub's newest family, whose vendored operations mirror the Actions ones byte-for-byte and reuse the identical components; served as `organization-actions-secret`, so `visibility` is published and `selected_repositories_url` only on a `selected` row - a link on an `all` row would advertise a route that answers 409. NO `value` MEMBER IS SERVED AND NONE EXISTS: `actions-secret` declares a name and two dates, `ci_binding.value` is NULL on every masked row, and conformance asserts the property is absent from every served secret rather than trusting the schema, which sets no `additionalProperties: false`", mode_reviewed: "2026-09-12", category: "agents", subcategory: "secrets", flag: "needs-tier-review" }
      - { method: "GET", path: "/orgs/{org}/agents/secrets/{secret_name}", area: "agents", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` + `ci_binding_scope` - the settings and credentials this organization hands its pipelines. GitHub publishes ONE object as two URL families, so a secret is a binding whose value may not be published and a variable is one whose value may; canon carries exactly that boolean (`masked`) and this row is the same read with a different filter. The `agents` family is canon's `coding-agent` audience - GitHub's newest family, whose vendored operations mirror the Actions ones byte-for-byte and reuse the identical components; a name the list published, never a name recomputed from the theme's pool. A name this organization does not hold is GitHub's own 404", mode_reviewed: "2026-09-12", category: "agents", subcategory: "secrets", flag: "needs-tier-review" }
      - { method: "GET", path: "/orgs/{org}/agents/secrets/{secret_name}/repositories", area: "agents", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` + `ci_binding_scope` - the settings and credentials this organization hands its pipelines. GitHub publishes ONE object as two URL families, so a secret is a binding whose value may not be published and a variable is one whose value may; canon carries exactly that boolean (`masked`) and this row is the same read with a different filter. The `agents` family is canon's `coding-agent` audience - GitHub's newest family, whose vendored operations mirror the Actions ones byte-for-byte and reuse the identical components; the repositories the secret actually reaches - `all` reaches every one, `private` the private ones, `selected` the named ones. The vendored operation declares NO 409 on the secret form (only the variable form does), so this answers the 200 whatever the visibility, and conformance fetches every repository it names to prove the link resolves", mode_reviewed: "2026-09-12", category: "agents", subcategory: "secrets", flag: "needs-tier-review" }
      - { method: "GET", path: "/orgs/{org}/agents/secrets/public-key", area: "agents", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` + `ci_binding_scope` - the settings and credentials this organization hands its pipelines. GitHub publishes ONE object as two URL families, so a secret is a binding whose value may not be published and a variable is one whose value may; canon carries exactly that boolean (`masked`) and this row is the same read with a different filter. The `agents` family is canon's `coding-agent` audience - GitHub's newest family, whose vendored operations mirror the Actions ones byte-for-byte and reuse the identical components; the scope's own 32 X25519 public-key bytes, base64-encoded, and its monotonic `key_id`. THE PUBLIC HALF IS REAL AND THERE IS NO PRIVATE HALF - this universe accepts no writes, so nothing is ever encrypted to these bytes; conformance base64-decodes them and asserts the length is 32 rather than accepting any string", mode_reviewed: "2026-09-12", category: "agents", subcategory: "secrets", flag: "needs-tier-review" }
      - { method: "GET", path: "/orgs/{org}/agents/variables", area: "agents", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` + `ci_binding_scope` - the settings and credentials this organization hands its pipelines. GitHub publishes ONE object as two URL families, so a secret is a binding whose value may not be published and a variable is one whose value may; canon carries exactly that boolean (`masked`) and this row is the same read with a different filter. The `agents` family is canon's `coding-agent` audience - GitHub's newest family, whose vendored operations mirror the Actions ones byte-for-byte and reuse the identical components; `organization-actions-variable`, whose `value` IS declared and is READ from the artifact row canon's `value_source` names - the telemetry exporter's endpoint and its protocol - so the setting and the thing it configures cannot drift apart", mode_reviewed: "2026-09-12", category: "agents", subcategory: "variables", flag: "needs-tier-review" }
      - { method: "GET", path: "/orgs/{org}/agents/variables/{name}", area: "agents", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` + `ci_binding_scope` - the settings and credentials this organization hands its pipelines. GitHub publishes ONE object as two URL families, so a secret is a binding whose value may not be published and a variable is one whose value may; canon carries exactly that boolean (`masked`) and this row is the same read with a different filter. The `agents` family is canon's `coding-agent` audience - GitHub's newest family, whose vendored operations mirror the Actions ones byte-for-byte and reuse the identical components; a name the list published. A name this organization does not hold is GitHub's own 404", mode_reviewed: "2026-09-12", category: "agents", subcategory: "variables", flag: "needs-tier-review" }
      - { method: "GET", path: "/orgs/{org}/agents/variables/{name}/repositories", area: "agents", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` + `ci_binding_scope` - the settings and credentials this organization hands its pipelines. GitHub publishes ONE object as two URL families, so a secret is a binding whose value may not be published and a variable is one whose value may; canon carries exactly that boolean (`masked`) and this row is the same read with a different filter. THE 409 BRANCH of the same operation, and the only answer this organization can give it: its one coding-agent variable is the workspace the agent operates in, which every repository sees, so its visibility is `all`. The vendored 409 declares no body and neither does this. The `actions` twin answers the 200, so the two rows together exercise both branches the document declares", mode_reviewed: "2026-09-12", category: "agents", subcategory: "variables", flag: "needs-tier-review" }
      - { method: "GET", path: "/orgs/{org}/artifacts/{subject_digest}/metadata/deployment-records", area: "artifact-metadata", tier: 3, status: "planned", mode: "generate", mode_reason: "new canon entity Attestation", category: "orgs", subcategory: "artifact-metadata" }
      - { method: "GET", path: "/orgs/{org}/artifacts/{subject_digest}/metadata/storage-records", area: "artifact-metadata", tier: 3, status: "planned", mode: "generate", mode_reason: "new canon entity Attestation", category: "orgs", subcategory: "artifact-metadata" }
      - { method: "GET", path: "/orgs/{org}/artifacts/metadata/deployment-record/cluster/{cluster}/jobs/{job_id}", area: "artifact-metadata", tier: 3, status: "planned", mode: "generate", mode_reason: "new canon entity Attestation", category: "orgs", subcategory: "artifact-metadata" }
      - { method: "GET", path: "/orgs/{org}/attestations/{subject_digest}", area: "attestations", tier: 3, status: "green", mode: "empty", mode_reason: "no artifact in this universe is attested — all 392 `artifact` rows are plain workflow-run uploads with no provenance bundle and none of the three workflows (`ci`, `lint`, `release`) runs an attestation step; GitHub's own answer for a subject digest with no attestations is `{attestations: []}` at 200 (the spec's 200 has NO required member). The operation also declares a 404 and the ORCHESTRATOR RULED the 200: a digest is a content address rather than a resource id, so asking about an artifact nobody signed is a well-formed question whose answer is \"none\". RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", category: "orgs", subcategory: "attestations" }
      - { method: "GET", path: "/orgs/{org}/attestations/repositories", area: "attestations", tier: 3, status: "green", mode: "empty", mode_reason: "no artifact in this universe is attested — all 392 `artifact` rows are plain workflow-run uploads with no provenance bundle and none of the three workflows (`ci`, `lint`, `release`) runs an attestation step; this operation's own 200 is a bare array of the repositories that have attestations, so its empty answer is `[]` rather than the `{attestations: []}` envelope the by-digest reads carry. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", category: "orgs", subcategory: "attestations" }
      - { method: "GET", path: "/orgs/{org}/blocks", area: "blocking", tier: 3, status: "green", mode: "empty", mode_reason: "nobody is blocked in this universe: the org's cast is its own employees and the outside contributors it works with, and a block only exists because someone created it", mode_reviewed: "2026-09-01", category: "orgs", subcategory: "blocking" }
      - { method: "GET", path: "/orgs/{org}/blocks/{username}", area: "blocking", tier: 3, status: "planned", mode: "refuse", mode_reason: "the id half of the org block pair: with nobody blocked, GitHub answers 404 to the per-user block check", mode_reviewed: "2026-09-01", category: "orgs", subcategory: "blocking" }
      - { method: "GET", path: "/orgs/{org}/campaigns", area: "campaigns", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityCampaign", category: "campaigns", subcategory: "campaigns", flag: "needs-tier-review" }
      - { method: "GET", path: "/orgs/{org}/campaigns/{campaign_number}", area: "campaigns", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityCampaign", category: "campaigns", subcategory: "campaigns", flag: "needs-tier-review" }
      - { method: "GET", path: "/orgs/{org}/code-scanning/alerts", area: "code-scanning", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityFinding", category: "code-scanning", subcategory: "code-scanning" }
      - { method: "GET", path: "/orgs/{org}/code-security/configurations", area: "code-security", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityConfiguration", category: "code-security", subcategory: "configurations", flag: "needs-tier-review" }
      - { method: "GET", path: "/orgs/{org}/code-security/configurations/{configuration_id}", area: "code-security", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityConfiguration", category: "code-security", subcategory: "configurations", flag: "needs-tier-review" }
      - { method: "GET", path: "/orgs/{org}/code-security/configurations/{configuration_id}/repositories", area: "code-security", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityConfiguration", category: "code-security", subcategory: "configurations", flag: "needs-tier-review" }
      - { method: "GET", path: "/orgs/{org}/code-security/configurations/defaults", area: "code-security", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityConfiguration", category: "code-security", subcategory: "configurations", flag: "needs-tier-review" }
      - { method: "GET", path: "/orgs/{org}/codespaces", area: "codespaces", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no persona in this universe launches a Codespace: every Codespaces object exists only because a write created one, and this universe accepts no writes", mode_reviewed: "2026-09-01", category: "codespaces", subcategory: "organizations", flag: "needs-tier-review" }
      - { method: "GET", path: "/orgs/{org}/codespaces/secrets", area: "codespaces", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no persona in this universe launches a Codespace: every Codespaces object exists only because a write created one, and this universe accepts no writes", mode_reviewed: "2026-09-01", category: "codespaces", subcategory: "organization-secrets", flag: "needs-tier-review" }
      - { method: "GET", path: "/orgs/{org}/codespaces/secrets/{secret_name}", area: "codespaces", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no persona in this universe launches a Codespace: every Codespaces object exists only because a write created one, and this universe accepts no writes", mode_reviewed: "2026-09-01", category: "codespaces", subcategory: "organization-secrets", flag: "needs-tier-review" }
      - { method: "GET", path: "/orgs/{org}/codespaces/secrets/{secret_name}/repositories", area: "codespaces", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no persona in this universe launches a Codespace: every Codespaces object exists only because a write created one, and this universe accepts no writes", mode_reviewed: "2026-09-01", category: "codespaces", subcategory: "organization-secrets", flag: "needs-tier-review" }
      - { method: "GET", path: "/orgs/{org}/codespaces/secrets/public-key", area: "codespaces", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no persona in this universe launches a Codespace: every Codespaces object exists only because a write created one, and this universe accepts no writes", mode_reviewed: "2026-09-01", category: "codespaces", subcategory: "organization-secrets", flag: "needs-tier-review" }
      - { method: "GET", path: "/orgs/{org}/copilot-spaces", area: "copilot-spaces", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity CopilotSpace", category: "copilot-spaces", subcategory: "copilot-spaces", flag: "needs-tier-review" }
      - { method: "GET", path: "/orgs/{org}/copilot-spaces/{space_number}", area: "copilot-spaces", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity CopilotSpace", category: "copilot-spaces", subcategory: "copilot-spaces", flag: "needs-tier-review" }
      - { method: "GET", path: "/orgs/{org}/copilot-spaces/{space_number}/collaborators", area: "copilot-spaces", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity CopilotSpace", category: "copilot-spaces", subcategory: "collaborators", flag: "needs-tier-review" }
      - { method: "GET", path: "/orgs/{org}/copilot-spaces/{space_number}/resources", area: "copilot-spaces", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity CopilotSpace", category: "copilot-spaces", subcategory: "resources", flag: "needs-tier-review" }
      - { method: "GET", path: "/orgs/{org}/copilot-spaces/{space_number}/resources/{space_resource_id}", area: "copilot-spaces", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity CopilotSpace", category: "copilot-spaces", subcategory: "resources", flag: "needs-tier-review" }
      - { method: "GET", path: "/orgs/{org}/copilot/billing", area: "copilot", tier: 2, status: "green", mode: "derive", category: "copilot", subcategory: "copilot-user-management" }
      - { method: "GET", path: "/orgs/{org}/copilot/billing/seats", area: "copilot", tier: 2, status: "green", mode: "derive", category: "copilot", subcategory: "copilot-user-management" }
      - { method: "GET", path: "/orgs/{org}/copilot/coding-agent/permissions", area: "copilot", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity CopilotPolicy", category: "copilot", subcategory: "copilot-coding-agent-management" }
      - { method: "GET", path: "/orgs/{org}/copilot/coding-agent/permissions/repositories", area: "copilot", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity CopilotPolicy", category: "copilot", subcategory: "copilot-coding-agent-management" }
      - { method: "GET", path: "/orgs/{org}/copilot/content_exclusion", area: "copilot", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity CopilotPolicy", category: "copilot", subcategory: "copilot-content-exclusion-management" }
      - { method: "GET", path: "/orgs/{org}/copilot/metrics", area: "copilot", tier: 2, status: "retired", mode: "derive", mode_reason: "served on the pins frozen before the retirement; the live host refuses it (meta.retired_meaning)", category: "copilot", subcategory: "copilot-metrics" }
      - { method: "GET", path: "/orgs/{org}/copilot/metrics/reports/organization-1-day", area: "copilot", tier: 2, status: "green", mode: "derive", category: "copilot", subcategory: "copilot-usage-metrics" }
      - { method: "GET", path: "/orgs/{org}/copilot/metrics/reports/organization-28-day/latest", area: "copilot", tier: 2, status: "green", mode: "derive", category: "copilot", subcategory: "copilot-usage-metrics" }
      - { method: "GET", path: "/orgs/{org}/copilot/metrics/reports/repos-1-day", area: "copilot", tier: 2, status: "green", mode: "derive", category: "copilot", subcategory: "copilot-usage-metrics" }
      - { method: "GET", path: "/orgs/{org}/copilot/metrics/reports/user-teams-1-day", area: "copilot", tier: 2, status: "green", mode: "derive", category: "copilot", subcategory: "copilot-usage-metrics" }
      - { method: "GET", path: "/orgs/{org}/copilot/metrics/reports/users-1-day", area: "copilot", tier: 2, status: "green", mode: "derive", category: "copilot", subcategory: "copilot-usage-metrics" }
      - { method: "GET", path: "/orgs/{org}/copilot/metrics/reports/users-28-day/latest", area: "copilot", tier: 2, status: "green", mode: "derive", category: "copilot", subcategory: "copilot-usage-metrics" }
      - { method: "GET", path: "/orgs/{org}/dependabot/alerts", area: "dependabot", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityFinding", category: "dependabot", subcategory: "alerts" }
      - { method: "GET", path: "/orgs/{org}/dependabot/repository-access", area: "dependabot", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityConfiguration", category: "dependabot", subcategory: "repository-access" }
      - { method: "GET", path: "/orgs/{org}/dependabot/secrets", area: "dependabot", tier: 3, status: "green", mode: "empty", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a) as GitHub's empty envelope at 200, by FOUNDER RULING F3 (2026-09-12): olympus-labs runs no private package registry, so a dependency bot has nothing private to reach and this organization holds no Dependabot secret. The SCOPE is real - canon mints it and `.../dependabot/secrets/public-key` is green beside this row, exactly as GitHub publishes a Dependabot public key whether or not a secret exists - and the empty list is only an honest `[]` once something says the scope exists, which is why this row is gated on `hasCiBindings()` and answers the generation on an older artifact. `compiler/src/hello19.test.ts` coherence check 9 asserts the emptiness in canon at both windows, so the ruling is falsifiable the day this organization gains a private registry", mode_reviewed: "2026-09-12", category: "dependabot", subcategory: "secrets" }
      - { method: "GET", path: "/orgs/{org}/dependabot/secrets/{secret_name}", area: "dependabot", tier: 3, status: "deferred", mode: "refuse", mode_reason: "REFUSED 2026-09-12 (hello-19 wave W-a) with GitHub's own 404: no name resolves over the empty collection founder ruling F3 leaves at this scope - olympus-labs runs no private package registry. Ungated across generations, because the absence is true on every artifact this project has produced", mode_reviewed: "2026-09-12", category: "dependabot", subcategory: "secrets" }
      - { method: "GET", path: "/orgs/{org}/dependabot/secrets/{secret_name}/repositories", area: "dependabot", tier: 3, status: "deferred", mode: "refuse", mode_reason: "REFUSED 2026-09-12 (hello-19 wave W-a) with GitHub's own 404: the secret whose repositories this asks for does not exist - see the by-name row beside it", mode_reviewed: "2026-09-12", category: "dependabot", subcategory: "secrets" }
      - { method: "GET", path: "/orgs/{org}/dependabot/secrets/public-key", area: "dependabot", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` + `ci_binding_scope` - the settings and credentials this organization hands its pipelines. GitHub publishes ONE object as two URL families, so a secret is a binding whose value may not be published and a variable is one whose value may; canon carries exactly that boolean (`masked`) and this row is the same read with a different filter. The Dependabot scope's own 32 X25519 public-key bytes. GREEN even though the collection beside it is empty by founder ruling F3, because that is exactly what GitHub does: the key is what a client would encrypt a NEW secret to, so it is published whether or not one exists", mode_reviewed: "2026-09-12", category: "dependabot", subcategory: "secrets" }
      - { method: "GET", path: "/orgs/{org}/docker/conflicts", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Package", category: "packages", subcategory: "packages" }
      - { method: "GET", path: "/orgs/{org}/events", area: "events-timeline", tier: 2, status: "green", mode: "derive", category: "activity", subcategory: "events" }
      - { method: "GET", path: "/orgs/{org}/failed_invitations", area: "orgs", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): the pending org memberships WITH `failed_epoch` — reader.listMemberships(\"org\", org) (reader.ts:2961). The failure is the clock's: `failed_epoch` IS `expires_epoch`, so nothing had to be invented to make an invitation fail and `failed_at` can never precede the offer — conformance asserts both, and that every row carries the reason the host printed", mode_reviewed: "2026-09-09", category: "orgs", subcategory: "members" }
      - { method: "GET", path: "/orgs/{org}/hooks", area: "webhooks-config", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-18 serving wave W-c): off `webhook_subscription`'s hello-18 git-host scopes (features.webhookFilters) through reader.orgWebhooks(), gated on hasWebhookFilters() so hello-17 and all eighty-one -g8..-g11 pins name the generation instead of claiming this organization configured no webhook. Canon stores NEUTRAL event names and this renderer spells them GitHub's way - ref.pushed->push, change.opened/change.merged->pull_request, issue.opened/issue.closed->issues, build.completed->check_run - many-to-one because GitHub subscribes by event NAME and puts the verb in the payload's `action`. The account-wide feed, a DIFFERENT row from PagerDuty's account-scoped subscription - which is why canon's filter vocabulary carries both scopes and why listWebhookSubscriptions() is scoped to the alerting kinds in the same PR as the widening.", mode_reviewed: "2026-09-12", category: "orgs", subcategory: "webhooks" }
      - { method: "GET", path: "/orgs/{org}/hooks/{hook_id}", area: "webhooks-config", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-18 serving wave W-c): off `webhook_subscription`'s hello-18 git-host scopes (features.webhookFilters) through reader.orgWebhooks(), gated on hasWebhookFilters() so hello-17 and all eighty-one -g8..-g11 pins name the generation instead of claiming this organization configured no webhook. Canon stores NEUTRAL event names and this renderer spells them GitHub's way - ref.pushed->push, change.opened/change.merged->pull_request, issue.opened/issue.closed->issues, build.completed->check_run - many-to-one because GitHub subscribes by event NAME and puts the verb in the payload's `action`. `org-hook` is a DIFFERENT schema from `hook` and the differences are honoured: it declares neither test_url nor last_response, so neither is emitted even though the row carries the delivery columns.", mode_reviewed: "2026-09-12", category: "orgs", subcategory: "webhooks" }
      - { method: "GET", path: "/orgs/{org}/hooks/{hook_id}/config", area: "webhooks-config", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-18 serving wave W-c): off `webhook_subscription`'s hello-18 git-host scopes (features.webhookFilters) through reader.orgWebhooks(), gated on hasWebhookFilters() so hello-17 and all eighty-one -g8..-g11 pins name the generation instead of claiming this organization configured no webhook. Canon stores NEUTRAL event names and this renderer spells them GitHub's way - ref.pushed->push, change.opened/change.merged->pull_request, issue.opened/issue.closed->issues, build.completed->check_run - many-to-one because GitHub subscribes by event NAME and puts the verb in the payload's `action`. The same `webhook-config` the repository pair serves, off the organization's own row - and conformance asserts the two scopes advertise DIFFERENT delivery URLs, because canon picks the receiver by scope.", mode_reviewed: "2026-09-12", category: "orgs", subcategory: "webhooks" }
      - { method: "GET", path: "/orgs/{org}/hooks/{hook_id}/deliveries", area: "webhooks-config", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Webhook", category: "orgs", subcategory: "webhooks" }
      - { method: "GET", path: "/orgs/{org}/hooks/{hook_id}/deliveries/{delivery_id}", area: "webhooks-config", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Webhook", category: "orgs", subcategory: "webhooks" }
      - { method: "GET", path: "/orgs/{org}/insights/api/route-stats/{actor_type}/{actor_id}", area: "api-insights", tier: 3, status: "planned", mode: "generate", mode_reason: "new canon entity ApiRequestStat", category: "orgs", subcategory: "api-insights" }
      - { method: "GET", path: "/orgs/{org}/insights/api/subject-stats", area: "api-insights", tier: 3, status: "planned", mode: "generate", mode_reason: "new canon entity ApiRequestStat", category: "orgs", subcategory: "api-insights" }
      - { method: "GET", path: "/orgs/{org}/insights/api/summary-stats", area: "api-insights", tier: 3, status: "planned", mode: "generate", mode_reason: "new canon entity ApiRequestStat", category: "orgs", subcategory: "api-insights" }
      - { method: "GET", path: "/orgs/{org}/insights/api/summary-stats/{actor_type}/{actor_id}", area: "api-insights", tier: 3, status: "planned", mode: "generate", mode_reason: "new canon entity ApiRequestStat", category: "orgs", subcategory: "api-insights" }
      - { method: "GET", path: "/orgs/{org}/insights/api/summary-stats/users/{user_id}", area: "api-insights", tier: 3, status: "planned", mode: "generate", mode_reason: "new canon entity ApiRequestStat", category: "orgs", subcategory: "api-insights" }
      - { method: "GET", path: "/orgs/{org}/insights/api/time-stats", area: "api-insights", tier: 3, status: "planned", mode: "generate", mode_reason: "new canon entity ApiRequestStat", category: "orgs", subcategory: "api-insights" }
      - { method: "GET", path: "/orgs/{org}/insights/api/time-stats/{actor_type}/{actor_id}", area: "api-insights", tier: 3, status: "planned", mode: "generate", mode_reason: "new canon entity ApiRequestStat", category: "orgs", subcategory: "api-insights" }
      - { method: "GET", path: "/orgs/{org}/insights/api/time-stats/users/{user_id}", area: "api-insights", tier: 3, status: "planned", mode: "generate", mode_reason: "new canon entity ApiRequestStat", category: "orgs", subcategory: "api-insights" }
      - { method: "GET", path: "/orgs/{org}/insights/api/user-stats/{user_id}", area: "api-insights", tier: 3, status: "planned", mode: "generate", mode_reason: "new canon entity ApiRequestStat", category: "orgs", subcategory: "api-insights" }
      - { method: "GET", path: "/orgs/{org}/installation", area: "apps", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity GitHubApp", category: "apps", subcategory: "apps", flag: "needs-tier-review" }
      - { method: "GET", path: "/orgs/{org}/installations", area: "orgs", tier: 1, status: "planned", mode: "generate", mode_reason: "new canon entity GitHubApp", category: "orgs", subcategory: "orgs" }
      - { method: "GET", path: "/orgs/{org}/interaction-limits", area: "interactions", tier: 3, status: "green", mode: "empty", mode_reason: "no interaction limit is active anywhere in this universe — olympus-labs is a private organization whose one repository is private (repo.visibility='private'), so there is no drive-by traffic to limit and nobody has set one; GitHub's own answer for a scope with no active limit is `{}` at 200 (the spec's 200 has no required member). RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", category: "interactions", subcategory: "orgs", flag: "needs-tier-review" }
      - { method: "GET", path: "/orgs/{org}/invitations", area: "orgs", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): the pending org memberships WITHOUT `failed_epoch` — reader.listMemberships(\"org\", org) (reader.ts:2961). An invitation is a membership that has not happened yet (`state: pending`, which is GitHub's own word for it on `team-membership`), so one column discriminates this surface from /orgs/{org}/failed_invitations and conformance asserts nothing appears on both. `login` and `email` are the pair GitHub types nullable on BOTH members because an invitation names a person or an address; canon sets exactly one, and the entry asserts the biconditional", mode_reviewed: "2026-09-09", category: "orgs", subcategory: "members" }
      - { method: "GET", path: "/orgs/{org}/invitations/{invitation_id}/teams", area: "orgs", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): the team a pending membership is scoped to — reader.listMemberships over org, team and repository scope (reader.ts:2961). A team-scoped invitation names its team and an organization-scoped one grants none, which is what `team_count` on the invitation object already says; conformance follows `invitation_teams_url` from every invitation and asserts the count and the list agree. An invitation id nobody holds is GitHub's own 404, not an empty list", mode_reviewed: "2026-09-09", category: "orgs", subcategory: "members" }
      - { method: "GET", path: "/orgs/{org}/issue-fields", area: "issue-fields", tier: 3, status: "planned", mode: "generate", mode_reason: "new canon entity IssueField", category: "orgs", subcategory: "issue-fields" }
      - { method: "GET", path: "/orgs/{org}/issue-types", area: "issue-types", tier: 3, status: "green", mode: "derive", mode_reason: "STALE REASON (\"new canon entity IssueType\"): there is no entity to build. GitHub's issue type is a NAME plus a nullable description, and the set this organization offers IS `select distinct kind from issue` — a closed canon vocabulary (bug, feature-request, incident, question, task) present in every generation. Conformance cross-checks the published list against every issue's kind in BOTH directions, so a type nothing can be and a kind nothing advertises are each red", mode_reviewed: "2026-09-12", category: "orgs", subcategory: "issue-types" }
      - { method: "GET", path: "/orgs/{org}/issues", area: "issues", tier: 1, status: "green", mode: "derive", mode_reason: "issue lists across the repo, org and authenticated persona", category: "issues", subcategory: "issues" }
      - { method: "GET", path: "/orgs/{org}/members", area: "orgs", tier: 1, status: "green", mode: "derive", category: "orgs", subcategory: "members" }
      - { method: "GET", path: "/orgs/{org}/members/{username}", area: "orgs", tier: 1, status: "green", mode: "derive", mode_reason: "membership check over team_member", category: "orgs", subcategory: "members" }
      - { method: "GET", path: "/orgs/{org}/members/{username}/codespaces", area: "codespaces", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no persona in this universe launches a Codespace: every Codespaces object exists only because a write created one, and this universe accepts no writes", mode_reviewed: "2026-09-01", category: "codespaces", subcategory: "organizations", flag: "needs-tier-review" }
      - { method: "GET", path: "/orgs/{org}/members/{username}/copilot", area: "copilot", tier: 2, status: "green", mode: "derive", category: "copilot", subcategory: "copilot-user-management" }
      - { method: "GET", path: "/orgs/{org}/memberships/{username}", area: "orgs", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): reader.membershipFor(\"org\", org, person) (packages/artifact/src/reader.ts:2977), validated against the vendored `org-membership`. Canon's five role keys collapse to GitHub's two — `owner` and `admin` both report `admin`, which is what GitHub itself reports for an organization owner — and `state` is canon's own word for the same fact. `permissions` is OMITTED rather than invented: its one member is `can_create_repository` and canon records no such grant. A login the organization does not carry is GitHub's own 404, which is what /orgs/{org}/members/{username} already answers for it", mode_reviewed: "2026-09-09", category: "orgs", subcategory: "members" }
      - { method: "GET", path: "/orgs/{org}/migrations", area: "migrations", tier: 3, status: "deferred", mode: "refuse", mode_reason: "a migration or a source import exists only because someone started one; this universe has never run either, so GitHub answers 404 for the job that was never created", mode_reviewed: "2026-09-01", category: "migrations", subcategory: "orgs" }
      - { method: "GET", path: "/orgs/{org}/migrations/{migration_id}", area: "migrations", tier: 3, status: "deferred", mode: "refuse", mode_reason: "a migration or a source import exists only because someone started one; this universe has never run either, so GitHub answers 404 for the job that was never created", mode_reviewed: "2026-09-01", category: "migrations", subcategory: "orgs" }
      - { method: "GET", path: "/orgs/{org}/migrations/{migration_id}/archive", area: "migrations", tier: 3, status: "deferred", mode: "refuse", mode_reason: "a migration or a source import exists only because someone started one; this universe has never run either, so GitHub answers 404 for the job that was never created", mode_reviewed: "2026-09-01", category: "migrations", subcategory: "orgs" }
      - { method: "GET", path: "/orgs/{org}/migrations/{migration_id}/repositories", area: "migrations", tier: 3, status: "deferred", mode: "refuse", mode_reason: "a migration or a source import exists only because someone started one; this universe has never run either, so GitHub answers 404 for the job that was never created", mode_reviewed: "2026-09-01", category: "migrations", subcategory: "orgs" }
      - { method: "GET", path: "/orgs/{org}/organization-roles", area: "organization-roles", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): reader.listMembershipRoles() (reader.ts:2985) in GitHub's `{total_count, roles}` envelope. Five catalog ROWS rather than an enum rendered at request time: the vendored `organization-role` REQUIRES a `permissions` array, and a permission list composed inside a renderer is a fact invented at serving time. `permissions` is canon's closed `scope:level` vocabulary, which the schema types `array<string>` with no enum; `base_role` is GitHub's own enum and is read off the same list's repository rung, so the two cannot disagree — conformance recomputes it", mode_reviewed: "2026-09-09", category: "orgs", subcategory: "organization-roles" }
      - { method: "GET", path: "/orgs/{org}/organization-roles/{role_id}", area: "organization-roles", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): the same catalog row by id — reader.listMembershipRoles() (reader.ts:2985) addressed by githubId(MembershipRoleRow.id), byte-identical to the row the catalog serves. An id the catalog does not carry is GitHub's own 404", mode_reviewed: "2026-09-09", category: "orgs", subcategory: "organization-roles" }
      - { method: "GET", path: "/orgs/{org}/organization-roles/{role_id}/teams", area: "organization-roles", tier: 3, status: "green", mode: "empty", mode_reason: "no team holds a custom organization role: the access domain attaches a role to a PERSON on their own membership (reader.listMemberships, packages/artifact/src/reader.ts:2961) and to nothing else, which is the same statement `user-role-assignment.assignment: direct` and its empty `inherited_from` make from the other side on the sibling row served 2026-09-09. SERVED 2026-09-10 as GitHub's empty array, behind the hello-16 generation gate and behind the role guard — an id the catalog does not carry is still GitHub's own 404 — RULED EMPTY by the founder 2026-09-10", mode_reviewed: "2026-09-10", category: "orgs", subcategory: "organization-roles" }
      - { method: "GET", path: "/orgs/{org}/organization-roles/{role_id}/users", area: "organization-roles", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): the active org memberships whose role is this catalog row's key — reader.listMemberships(\"org\", org) (reader.ts:2961). Conformance asserts the holders of all five roles TOGETHER are exactly the member list, so the catalog partitions the organization rather than covering part of it. `maintainer` and `reader` have no holders at org scope — maintainer is repository-scoped here and this universe has no outside contributor — which is a fact about the organization, not a gap", mode_reviewed: "2026-09-09", category: "orgs", subcategory: "organization-roles" }
      - { method: "GET", path: "/orgs/{org}/outside_collaborators", area: "orgs", tier: 1, status: "green", mode: "empty", mode_reason: "NOBODY IN THIS UNIVERSE IS OUTSIDE THE ORGANIZATION. The 2026-09-01 classification guessed the opposite — 'canon already marks outside contributors (Person.member = false)' — and no row satisfies it: every person carries member = 1, so `orgMembers()` and `listPeople()` return the same set and the outside-collaborator list is truthfully empty. It is also the fact the collaborator endpoints already publish, since `/repos/{o}/{r}/collaborators?affiliation=outside` answers `[]` for the same reason. Falsifiable: the day the generator gives the org a contributor with member = 0, this row goes red rather than hiding them. RULED by the founder 2026-09-09", mode_reviewed: "2026-09-09", category: "orgs", subcategory: "outside-collaborators" }
      - { method: "GET", path: "/orgs/{org}/packages", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Package", category: "packages", subcategory: "packages" }
      - { method: "GET", path: "/orgs/{org}/packages/{package_type}/{package_name}", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Package", category: "packages", subcategory: "packages" }
      - { method: "GET", path: "/orgs/{org}/packages/{package_type}/{package_name}/versions", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Package", category: "packages", subcategory: "packages" }
      - { method: "GET", path: "/orgs/{org}/packages/{package_type}/{package_name}/versions/{package_version_id}", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Package", category: "packages", subcategory: "packages" }
      - { method: "GET", path: "/orgs/{org}/personal-access-token-requests", area: "personal-access-tokens", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): reader.credentialRequests() behind reader.hasCallerCredentials(), validated against `organization-programmatic-access-grant-request`. THE hello-16 ASK IS ANSWERED: that wave said canon modelled no pending token request, and hello-17 adds \"pending\" to CredentialState with a request_reason column (decisions/2026-09-11-0151) — the org's newest engineer asks for the scope their first blocked act needed, at the instant of that act. THE ROWS ARE REACHABLE THROUGH ONE ACCESSOR AND NOWHERE ELSE: credentialScope() excludes `pending` from credentialsForPerson and listCredentials, so /orgs/{org}/personal-access-tokens cannot serve a request as a grant by forgetting a filter, and conformance asserts the two ledgers share no token_id and no id. `token_expired: false`, `token_expires_at: null` and `token_last_used_at: null` are not defaults — the generator throws if a pending row carries an expiry, an end or a use, because a request has never been a token. A hello-16 artifact answers the hello-17 generation gap and NOT hello-16's: it HAS the person_credential table — somebody else's keys are served off it — and none of these rows, which is why the gate is reader.hasCallerCredentials() and not reader.hasCredentials().", mode_reviewed: "2026-09-12", category: "orgs", subcategory: "personal-access-tokens" }
      - { method: "GET", path: "/orgs/{org}/personal-access-token-requests/{pat_request_id}/repositories", area: "personal-access-tokens", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): what the requested token would reach. `repository_selection` is `all` for the reason the granted twin gives — canon's personal-token acts as its owner everywhere its owner can act and carries no scope_ref, and every repository here belongs to the organization — so the answer is the organization's repositories through the same orgReposResponse /orgs/{org}/personal-access-tokens/{pat_id}/repositories uses. One request, one answer, and the two routes cannot describe different repositories; conformance asserts they agree and that an unminted pat_request_id is a 404. A hello-16 artifact answers the hello-17 generation gap and NOT hello-16's: it HAS the person_credential table — somebody else's keys are served off it — and none of these rows, which is why the gate is reader.hasCallerCredentials() and not reader.hasCredentials().", mode_reviewed: "2026-09-12", category: "orgs", subcategory: "personal-access-tokens" }
      - { method: "GET", path: "/orgs/{org}/personal-access-tokens", area: "personal-access-tokens", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): reader.listCredentials(\"personal-token\") (reader.ts:3026), validated against `organization-programmatic-access-grant`. Every repository in this universe belongs to the organization, so every personal token that reaches a repository reaches an organization resource and no scope filter had to be invented to decide which tokens count. Canon's provider-neutral `TokenScope`s are mapped ONCE, in packages/renderer-github/src/render-credentials.ts, into GitHub's fine-grained `{organization, repository, other}` permission spelling (the WorkflowStateKey precedent), and the table is TOTAL — an unmapped scope throws rather than being silently dropped. METADATA ONLY: a token's value is shown once at creation by the provider we replicate reads of, so canon holds none (the PagerDuty routing-key rule, DECISIONS 2026-09-03) and conformance asserts no served byte is shaped like one", mode_reviewed: "2026-09-09", category: "orgs", subcategory: "personal-access-tokens" }
      - { method: "GET", path: "/orgs/{org}/personal-access-tokens/{pat_id}/repositories", area: "personal-access-tokens", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): what a granted token reaches. `repository_selection` is `all` on every grant — a personal token acts as its owner wherever its owner can act and carries no `scope_ref` — so the answer is the organization's repositories through the same shaper /orgs/{org}/repos uses, and conformance asserts the two lists are identical. `pat_id` is the GRANT's own id and not the token's: the two are distinct numbers on one object, and the entry asserts the token id does NOT address it", mode_reviewed: "2026-09-09", category: "orgs", subcategory: "personal-access-tokens" }
      - { method: "GET", path: "/orgs/{org}/private-registries", area: "private-registries", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity PrivateRegistryConfig", category: "private-registries", subcategory: "organization-configurations", flag: "needs-tier-review" }
      - { method: "GET", path: "/orgs/{org}/private-registries/{secret_name}", area: "private-registries", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity PrivateRegistryConfig", category: "private-registries", subcategory: "organization-configurations", flag: "needs-tier-review" }
      - { method: "GET", path: "/orgs/{org}/private-registries/public-key", area: "private-registries", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity PrivateRegistryConfig", category: "private-registries", subcategory: "organization-configurations", flag: "needs-tier-review" }
      - { method: "GET", path: "/orgs/{org}/projectsV2", area: "projects-v2", tier: 2, status: "green", mode: "derive", mode_reason: "STALE REASON (\"new canon entity Board\"): a projectsV2 PROJECT is not a board. It is a titled, dated container of issues with an owner, a creator and an open/closed state, which is canon's `epic` exactly (22 rows) — the same entity renderer-linear/src/pm.ts already publishes as a Linear project. The BOARD (its views, columns and field definitions) is the part canon still lacks and no row here publishes one. Gated on hello-16's portfolio columns, four of which are REQUIRED members of `projects-v2`", mode_reviewed: "2026-09-12", category: "projects", subcategory: "projects" }
      - { method: "GET", path: "/orgs/{org}/projectsV2/{project_number}", area: "projects-v2", tier: 2, status: "green", mode: "derive", mode_reason: "STALE REASON (\"new canon entity Board\"): a projectsV2 PROJECT is not a board. It is a titled, dated container of issues with an owner, a creator and an open/closed state, which is canon's `epic` exactly (22 rows) — the same entity renderer-linear/src/pm.ts already publishes as a Linear project. The BOARD (its views, columns and field definitions) is the part canon still lacks and no row here publishes one. Gated on hello-16's portfolio columns, four of which are REQUIRED members of `projects-v2`", mode_reviewed: "2026-09-12", category: "projects", subcategory: "projects" }
      - { method: "GET", path: "/orgs/{org}/projectsV2/{project_number}/fields", area: "projects-v2", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Board", category: "projects", subcategory: "fields" }
      - { method: "GET", path: "/orgs/{org}/projectsV2/{project_number}/fields/{field_id}", area: "projects-v2", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Board", category: "projects", subcategory: "fields" }
      - { method: "GET", path: "/orgs/{org}/projectsV2/{project_number}/items", area: "projects-v2", tier: 2, status: "green", mode: "derive", mode_reason: "STALE REASON (\"new canon entity Board\"): the items of an epic ARE its issues (reader.epicIssues()), and each item's `content` is the object `/repos/{owner}/{repo}/issues/{issue_number}` already serves — so the two cross-check. Every item is an `Issue`: canon attaches a pull request to an issue rather than to an epic, and a draft issue exists only because somebody typed one into a project", mode_reviewed: "2026-09-12", category: "projects", subcategory: "items" }
      - { method: "GET", path: "/orgs/{org}/projectsV2/{project_number}/items/{item_id}", area: "projects-v2", tier: 2, status: "green", mode: "derive", mode_reason: "STALE REASON (\"new canon entity Board\"): the items of an epic ARE its issues (reader.epicIssues()), and each item's `content` is the object `/repos/{owner}/{repo}/issues/{issue_number}` already serves — so the two cross-check. Every item is an `Issue`: canon attaches a pull request to an issue rather than to an epic, and a draft issue exists only because somebody typed one into a project", mode_reviewed: "2026-09-12", category: "projects", subcategory: "items" }
      - { method: "GET", path: "/orgs/{org}/projectsV2/{project_number}/views/{view_number}/items", area: "projects-v2", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Board", category: "projects", subcategory: "items" }
      - { method: "GET", path: "/orgs/{org}/properties/schema", area: "custom-properties", tier: 3, status: "planned", mode: "generate", mode_reason: "new canon entity CustomProperty", category: "orgs", subcategory: "custom-properties" }
      - { method: "GET", path: "/orgs/{org}/properties/schema/{custom_property_name}", area: "custom-properties", tier: 3, status: "planned", mode: "generate", mode_reason: "new canon entity CustomProperty", category: "orgs", subcategory: "custom-properties" }
      - { method: "GET", path: "/orgs/{org}/properties/values", area: "custom-properties", tier: 3, status: "planned", mode: "generate", mode_reason: "new canon entity CustomProperty", category: "orgs", subcategory: "custom-properties" }
      - { method: "GET", path: "/orgs/{org}/public_members", area: "orgs", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): reader.listMemberships(\"org\", org) (reader.ts:2961), narrowed to the active rows whose `publicized` bit is set. `publicized` is the ONE drawn preference in the access domain (the `disableSsh` exception) and is roughly half the roster, so this is neither the member list under a second name nor an empty one — the conformance entry asserts both bounds against /orgs/{org}/members and that every public login is a member. Paginated with GitHub's Link header, walked to the last page", mode_reviewed: "2026-09-09", category: "orgs", subcategory: "members" }
      - { method: "GET", path: "/orgs/{org}/public_members/{username}", area: "orgs", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): reader.membershipFor(\"org\", org, person) (reader.ts:2977). GitHub answers this operation with a STATUS and no body — its documented 204 when the membership is public and its 404 when it is not — so the conformance entry asserts the three-way outcome (public 204, member-who-does-not-publicise 404, stranger 404) rather than a schema", mode_reviewed: "2026-09-09", category: "orgs", subcategory: "members" }
      - { method: "GET", path: "/orgs/{org}/repos", area: "repos", tier: 1, status: "green", mode: "derive", category: "repos", subcategory: "repos" }
      - { method: "GET", path: "/orgs/{org}/rulesets", area: "rulesets", tier: 3, status: "green", mode: "empty", mode_reason: "no ruleset exists at either scope — canon's only ref-protection rows (`protected_ref`, 2) are scoped to `namespace-001`, a container GitHub has no counterpart for, and repo-01 carries an empty `namespace` column; classic branch protection on `main` (branch.protected=1, served by render-protection.ts) is GitHub's OTHER mechanism and does not imply a ruleset, so GitHub's own answer for a scope with no rulesets is `[]` at 200. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", category: "orgs", subcategory: "rules" }
      - { method: "GET", path: "/orgs/{org}/rulesets/{ruleset_id}", area: "rulesets", tier: 3, status: "planned", mode: "generate", mode_reason: "new canon entity Ruleset", category: "orgs", subcategory: "rules" }
      - { method: "GET", path: "/orgs/{org}/rulesets/{ruleset_id}/history", area: "rulesets", tier: 3, status: "planned", mode: "generate", mode_reason: "new canon entity Ruleset", category: "orgs", subcategory: "rules" }
      - { method: "GET", path: "/orgs/{org}/rulesets/{ruleset_id}/history/{version_id}", area: "rulesets", tier: 3, status: "planned", mode: "generate", mode_reason: "new canon entity Ruleset", category: "orgs", subcategory: "rules" }
      - { method: "GET", path: "/orgs/{org}/rulesets/rule-suites", area: "rulesets", tier: 3, status: "green", mode: "empty", mode_reason: "no ruleset exists at either scope — canon's only ref-protection rows (`protected_ref`, 2) are scoped to `namespace-001`, a container GitHub has no counterpart for, and repo-01 carries an empty `namespace` column; classic branch protection on `main` (branch.protected=1, served by render-protection.ts) is GitHub's OTHER mechanism and does not imply a ruleset, so GitHub's own answer for a scope with no rulesets is `[]` at 200. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", category: "orgs", subcategory: "rule-suites" }
      - { method: "GET", path: "/orgs/{org}/rulesets/rule-suites/{rule_suite_id}", area: "rulesets", tier: 3, status: "planned", mode: "generate", mode_reason: "new canon entity Ruleset", category: "orgs", subcategory: "rule-suites" }
      - { method: "GET", path: "/orgs/{org}/secret-scanning/alerts", area: "secret-scanning", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityFinding", category: "secret-scanning", subcategory: "secret-scanning" }
      - { method: "GET", path: "/orgs/{org}/secret-scanning/custom-patterns", area: "secret-scanning", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityConfiguration", category: "secret-scanning", subcategory: "custom-patterns" }
      - { method: "GET", path: "/orgs/{org}/secret-scanning/pattern-configurations", area: "secret-scanning", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityConfiguration", category: "secret-scanning", subcategory: "push-protection" }
      - { method: "GET", path: "/orgs/{org}/security-advisories", area: "security-advisories", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityAdvisory", category: "security-advisories", subcategory: "repository-advisories", flag: "needs-tier-review" }
      - { method: "GET", path: "/orgs/{org}/security-managers", area: "security-managers", tier: 3, status: "green", mode: "empty", mode_reason: "no security managers are configured: `membership` records what each membership GRANTS and MEMBERSHIP_PERMISSIONS (packages/canon/src/access.ts) has no security rung at all — org, team, repo and namespace, five levels each — so naming a team here would hand it a grant nothing in this universe made. SERVED 2026-09-10 as GitHub's empty array, behind the hello-16 generation gate; falsifiable the day canon confers the authority — RULED EMPTY by the founder 2026-09-10", mode_reviewed: "2026-09-10", category: "orgs", subcategory: "security-managers" }
      - { method: "GET", path: "/orgs/{org}/settings/immutable-releases", area: "orgs", tier: 1, status: "planned", mode: "generate", mode_reason: "new canon entity RepoSettings", category: "orgs", subcategory: "orgs" }
      - { method: "GET", path: "/orgs/{org}/settings/immutable-releases/repositories", area: "orgs", tier: 1, status: "green", mode: "empty", mode_reason: "immutable releases are not enabled on olympus-labs/parthenon — its three `release` rows carry no immutability marker and canon has no repository release-immutability setting; GitHub's own answer for a repository where immutable releases are not enabled is 404 with no body (the spec's own 404 description), and the ORGANIZATION's selected-repository list is therefore an empty `{total_count: 0, repositories: []}` at 200. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", category: "orgs", subcategory: "orgs" }
      - { method: "GET", path: "/orgs/{org}/settings/network-configurations", area: "network-configurations", tier: 3, status: "planned", mode: "generate", mode_reason: "new canon entity NetworkConfiguration", category: "orgs", subcategory: "network-configurations" }
      - { method: "GET", path: "/orgs/{org}/settings/network-configurations/{network_configuration_id}", area: "network-configurations", tier: 3, status: "planned", mode: "generate", mode_reason: "new canon entity NetworkConfiguration", category: "orgs", subcategory: "network-configurations" }
      - { method: "GET", path: "/orgs/{org}/settings/network-settings/{network_settings_id}", area: "network-configurations", tier: 3, status: "planned", mode: "generate", mode_reason: "new canon entity NetworkConfiguration", category: "orgs", subcategory: "network-configurations" }
      - { method: "GET", path: "/orgs/{org}/teams", area: "teams", tier: 1, status: "green", mode: "derive", category: "teams", subcategory: "teams" }
      - { method: "GET", path: "/orgs/{org}/teams/{team_slug}", area: "teams", tier: 1, status: "green", mode: "derive", category: "teams", subcategory: "teams" }
      - { method: "GET", path: "/orgs/{org}/teams/{team_slug}/invitations", area: "teams", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): the pending TEAM memberships — reader.listMemberships(\"team\", team) (reader.ts:2961), rendered in the `organization-invitation` shape the operation declares. The invitee is somebody this organization already knows, so `login` is set and `email` is null, and the same row answers /orgs/{org}/teams/{team_slug}/memberships/{username} with `state: pending`", mode_reviewed: "2026-09-09", category: "teams", subcategory: "members" }
      - { method: "GET", path: "/orgs/{org}/teams/{team_slug}/members", area: "teams", tier: 1, status: "green", mode: "derive", category: "teams", subcategory: "members" }
      - { method: "GET", path: "/orgs/{org}/teams/{team_slug}/memberships/{username}", area: "teams", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): reader.membershipFor(\"team\", team, person) (reader.ts:2977), validated against `team-membership`. `state: pending` is real on this universe — one person is on a team's roster by invitation and not yet by membership — and /orgs/{org}/teams/{team_slug}/invitations serves that same row from the other side", mode_reviewed: "2026-09-09", category: "teams", subcategory: "members" }
      - { method: "GET", path: "/orgs/{org}/teams/{team_slug}/repos", area: "teams", tier: 1, status: "green", mode: "derive", category: "teams", subcategory: "teams" }
      - { method: "GET", path: "/orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}", area: "teams", tier: 1, status: "green", mode: "derive", mode_reason: "teams, their repo grants and the caller's own team list, over team/team_member", category: "teams", subcategory: "teams" }
      - { method: "GET", path: "/orgs/{org}/teams/{team_slug}/teams", area: "teams", tier: 1, status: "green", mode: "empty", mode_reason: "the org's teams are flat — four discipline teams, none nested under another — so a team's child-team list is truthfully empty", mode_reviewed: "2026-09-01", category: "teams", subcategory: "teams" }
      - { method: "GET", path: "/rate_limit", area: "rate-limit", tier: 1, status: "green", mode: "derive", category: "rate-limit", subcategory: "rate-limit" }
      - { method: "GET", path: "/repos/{owner}/{repo}", area: "repos", tier: 1, status: "green", mode: "derive", category: "repos", subcategory: "repos" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/artifacts", area: "actions", tier: 2, status: "green", mode: "derive", category: "actions", subcategory: "artifacts" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/artifacts/{artifact_id}", area: "actions", tier: 2, status: "green", mode: "derive", category: "actions", subcategory: "artifacts" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/artifacts/{artifact_id}/{archive_format}", area: "actions", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09: the SIXTH download redirect, on the founder-ruled 2026-09-02 pattern — the documented 302 to the service host, and the bytes behind it. reader.artifactContent(artifactId) (packages/artifact/src/reader.ts:2825) is the artifact's canonical content, packed by buildZip (packages/renderer-github/src/archive.ts:181) under ArtifactRow.path with the run's completion epoch as the mtime, so the archive is byte-identical on every request. `archive_download_url` on every artifact object has pointed here since Phase C, and conformance follows THAT url. `zip` is the only archive_format GitHub accepts; anything else is its 404. Answers the hello-15 generation gap rather than redirecting to an empty zip", mode_reviewed: "2026-09-09", category: "actions", subcategory: "artifacts" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/cache/retention-limit", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsCache", category: "actions", subcategory: "cache" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/cache/storage-limit", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsCache", category: "actions", subcategory: "cache" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/cache/usage", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsCache", category: "actions", subcategory: "cache" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/caches", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsCache", category: "actions", subcategory: "cache" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/concurrency_groups", area: "actions", tier: 2, status: "green", mode: "empty", mode_reason: "every workflow run in this universe has reached a terminal conclusion, so no concurrency group is active; the check goes red the day canon grows an in-flight run", mode_reviewed: "2026-09-01", category: "actions", subcategory: "concurrency-groups" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/concurrency_groups/{concurrency_group_name}", area: "actions", tier: 2, status: "deferred", mode: "refuse", mode_reason: "the name half of the concurrency-group pair: with no group active, GitHub answers 404 for the group that does not exist", mode_reviewed: "2026-09-01", category: "actions", subcategory: "concurrency-groups" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/jobs/{job_id}", area: "actions", tier: 2, status: "green", mode: "derive", category: "actions", subcategory: "workflow-jobs" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/jobs/{job_id}/logs", area: "actions", tier: 2, status: "green", mode: "derive", mode_reason: "hello-13 JobLog carries this job's log text; the documented 302 is simulated in-app (founder ruling 2026-09-02) — the Location names a signed route on the service host that serves those exact bytes as text/plain", mode_reviewed: "2026-09-02", category: "actions", subcategory: "workflow-jobs" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/oidc/customization/sub", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsPolicy", category: "actions", subcategory: "oidc" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/organization-secrets", area: "actions", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` + `ci_binding_scope` - the settings and credentials this organization hands its pipelines. GitHub publishes ONE object as two URL families, so a secret is a binding whose value may not be published and a variable is one whose value may; canon carries exactly that boolean (`masked`) and this row is the same read with a different filter. The `actions` family is canon's `pipeline` audience; the ORGANIZATION secrets this repository can see, and the visibility rule that decides which lives in `reader.orgBindingsVisibleToRepo` rather than in four renderers. Served as the PLAIN `actions-secret`, not the organization form - the vendored operation names that component here - so no `visibility` is published on this surface even though the rows are the organization's", mode_reviewed: "2026-09-12", category: "actions", subcategory: "secrets" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/organization-variables", area: "actions", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` + `ci_binding_scope` - the settings and credentials this organization hands its pipelines. GitHub publishes ONE object as two URL families, so a secret is a binding whose value may not be published and a variable is one whose value may; canon carries exactly that boolean (`masked`) and this row is the same read with a different filter. The `actions` family is canon's `pipeline` audience; the organization variables this repository can see, through the same reader rule as its secret twin", mode_reviewed: "2026-09-12", category: "actions", subcategory: "variables" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/permissions", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsPolicy", category: "actions", subcategory: "permissions" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/permissions/access", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsPolicy", category: "actions", subcategory: "permissions" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/permissions/artifact-and-log-retention", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsPolicy", category: "actions", subcategory: "permissions" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/permissions/fork-pr-contributor-approval", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsPolicy", category: "actions", subcategory: "permissions" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/permissions/fork-pr-workflows-private-repos", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsPolicy", category: "actions", subcategory: "permissions" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/permissions/selected-actions", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsPolicy", category: "actions", subcategory: "permissions" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/permissions/workflow", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsPolicy", category: "actions", subcategory: "permissions" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/runners", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Runner", category: "actions", subcategory: "self-hosted-runners" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/runners/{runner_id}", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Runner", category: "actions", subcategory: "self-hosted-runners" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/runners/{runner_id}/labels", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Runner", category: "actions", subcategory: "self-hosted-runners" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/runners/downloads", area: "actions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Runner", category: "actions", subcategory: "self-hosted-runners" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/runs", area: "actions", tier: 2, status: "green", mode: "derive", category: "actions", subcategory: "workflow-runs" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/runs/{run_id}", area: "actions", tier: 2, status: "green", mode: "derive", category: "actions", subcategory: "workflow-runs" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/runs/{run_id}/approvals", area: "actions", tier: 2, status: "green", mode: "empty", mode_reason: "no workflow run in this universe ever waited for an approval — all 398 `workflow_run` rows carry a terminal `conclusion` and the table has no pending state; GitHub's own answer for a run with no approval history is `[]` at 200. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", category: "actions", subcategory: "workflow-runs" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/runs/{run_id}/artifacts", area: "actions", tier: 2, status: "green", mode: "derive", category: "actions", subcategory: "artifacts" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/runs/{run_id}/attempts/{attempt_number}", area: "actions", tier: 2, status: "green", mode: "derive", category: "actions", subcategory: "workflow-runs" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/runs/{run_id}/attempts/{attempt_number}/jobs", area: "actions", tier: 2, status: "green", mode: "derive", category: "actions", subcategory: "workflow-jobs" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/runs/{run_id}/attempts/{attempt_number}/logs", area: "actions", tier: 2, status: "green", mode: "derive", mode_reason: "hello-13 JobLog carries every job's log text, so the attempt's zip is a container around canon; the documented 302 is simulated in-app (founder ruling 2026-09-02) and an attempt number this run never had stays a plain 404", mode_reviewed: "2026-09-02", category: "actions", subcategory: "workflow-runs" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/runs/{run_id}/concurrency_groups", area: "actions", tier: 2, status: "green", mode: "empty", mode_reason: "the per-run twin of the repository concurrency-group list, held to the same fact: every workflow run has reached a terminal conclusion, so none holds a concurrency group", mode_reviewed: "2026-09-01", category: "actions", subcategory: "concurrency-groups" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/runs/{run_id}/jobs", area: "actions", tier: 2, status: "green", mode: "derive", category: "actions", subcategory: "workflow-jobs" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/runs/{run_id}/logs", area: "actions", tier: 2, status: "green", mode: "derive", mode_reason: "hello-13 JobLog carries every job's log text, so the run's zip is a container around canon, one member per job; the documented 302 is simulated in-app (founder ruling 2026-09-02)", mode_reviewed: "2026-09-02", category: "actions", subcategory: "workflow-runs" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/runs/{run_id}/pending_deployments", area: "actions", tier: 2, status: "green", mode: "empty", mode_reason: "no workflow run in this universe ever waited for an approval — all 398 `workflow_run` rows carry a terminal `conclusion` and the table has no pending state; GitHub's own answer for a run with no approval history is `[]` at 200. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", category: "actions", subcategory: "workflow-runs" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/runs/{run_id}/timing", area: "actions", tier: 2, status: "green", mode: "derive", category: "actions", subcategory: "workflow-runs" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/secrets", area: "actions", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` + `ci_binding_scope` - the settings and credentials this organization hands its pipelines. GitHub publishes ONE object as two URL families, so a secret is a binding whose value may not be published and a variable is one whose value may; canon carries exactly that boolean (`masked`) and this row is the same read with a different filter. The `actions` family is canon's `pipeline` audience; the repository's OWN secrets. Two of them are backed by a `person_credential` this organization really issued - the registry pull token and the integration-suite token, whose two dates are the ROTATION PAIR canon records - so their instants are facts rather than plausible numbers", mode_reviewed: "2026-09-12", category: "actions", subcategory: "secrets" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/secrets/{secret_name}", area: "actions", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` + `ci_binding_scope` - the settings and credentials this organization hands its pipelines. GitHub publishes ONE object as two URL families, so a secret is a binding whose value may not be published and a variable is one whose value may; canon carries exactly that boolean (`masked`) and this row is the same read with a different filter. The `actions` family is canon's `pipeline` audience; a name the list published", mode_reviewed: "2026-09-12", category: "actions", subcategory: "secrets" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/secrets/public-key", area: "actions", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` + `ci_binding_scope` - the settings and credentials this organization hands its pipelines. GitHub publishes ONE object as two URL families, so a secret is a binding whose value may not be published and a variable is one whose value may; canon carries exactly that boolean (`masked`) and this row is the same read with a different filter. The `actions` family is canon's `pipeline` audience; the repository scope's own 32 public-key bytes", mode_reviewed: "2026-09-12", category: "actions", subcategory: "secrets" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/variables", area: "actions", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` + `ci_binding_scope` - the settings and credentials this organization hands its pipelines. GitHub publishes ONE object as two URL families, so a secret is a binding whose value may not be published and a variable is one whose value may; canon carries exactly that boolean (`masked`) and this row is the same read with a different filter. The repository's own published settings: its default branch and the tree path the orb document really sits at, both READ from the rows they name so a client that follows either finds the thing it points at", mode_reviewed: "2026-09-12", category: "actions", subcategory: "variables" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/variables/{name}", area: "actions", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` + `ci_binding_scope` - the settings and credentials this organization hands its pipelines. GitHub publishes ONE object as two URL families, so a secret is a binding whose value may not be published and a variable is one whose value may; canon carries exactly that boolean (`masked`) and this row is the same read with a different filter. A name the list published", mode_reviewed: "2026-09-12", category: "actions", subcategory: "variables" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/workflows", area: "actions", tier: 2, status: "green", mode: "derive", category: "actions", subcategory: "workflows" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/workflows/{workflow_id}", area: "actions", tier: 2, status: "green", mode: "derive", category: "actions", subcategory: "workflows" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/workflows/{workflow_id}/runs", area: "actions", tier: 2, status: "green", mode: "derive", category: "actions", subcategory: "workflow-runs" }
      - { method: "GET", path: "/repos/{owner}/{repo}/actions/workflows/{workflow_id}/timing", area: "actions", tier: 2, status: "green", mode: "derive", category: "actions", subcategory: "workflows" }
      - { method: "GET", path: "/repos/{owner}/{repo}/activity", area: "repos", tier: 1, status: "green", mode: "derive", category: "repos", subcategory: "repos" }
      - { method: "GET", path: "/repos/{owner}/{repo}/agents/organization-secrets", area: "agents", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` + `ci_binding_scope` - the settings and credentials this organization hands its pipelines. GitHub publishes ONE object as two URL families, so a secret is a binding whose value may not be published and a variable is one whose value may; canon carries exactly that boolean (`masked`) and this row is the same read with a different filter. The `agents` family is canon's `coding-agent` audience; the ORGANIZATION secrets this repository can see, and the visibility rule that decides which lives in `reader.orgBindingsVisibleToRepo` rather than in four renderers. Served as the PLAIN `actions-secret`, not the organization form - the vendored operation names that component here - so no `visibility` is published on this surface even though the rows are the organization's", mode_reviewed: "2026-09-12", category: "agents", subcategory: "secrets", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/agents/organization-variables", area: "agents", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` + `ci_binding_scope` - the settings and credentials this organization hands its pipelines. GitHub publishes ONE object as two URL families, so a secret is a binding whose value may not be published and a variable is one whose value may; canon carries exactly that boolean (`masked`) and this row is the same read with a different filter. The `agents` family is canon's `coding-agent` audience; the organization variables this repository can see, through the same reader rule as its secret twin", mode_reviewed: "2026-09-12", category: "agents", subcategory: "variables", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/agents/secrets", area: "agents", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` + `ci_binding_scope` - the settings and credentials this organization hands its pipelines. GitHub publishes ONE object as two URL families, so a secret is a binding whose value may not be published and a variable is one whose value may; canon carries exactly that boolean (`masked`) and this row is the same read with a different filter. The `agents` family is canon's `coding-agent` audience; the repository's OWN secrets. Two of them are backed by a `person_credential` this organization really issued - the registry pull token and the integration-suite token, whose two dates are the ROTATION PAIR canon records - so their instants are facts rather than plausible numbers", mode_reviewed: "2026-09-12", category: "agents", subcategory: "secrets", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/agents/secrets/{secret_name}", area: "agents", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` + `ci_binding_scope` - the settings and credentials this organization hands its pipelines. GitHub publishes ONE object as two URL families, so a secret is a binding whose value may not be published and a variable is one whose value may; canon carries exactly that boolean (`masked`) and this row is the same read with a different filter. The `agents` family is canon's `coding-agent` audience; a name the list published", mode_reviewed: "2026-09-12", category: "agents", subcategory: "secrets", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/agents/secrets/public-key", area: "agents", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` + `ci_binding_scope` - the settings and credentials this organization hands its pipelines. GitHub publishes ONE object as two URL families, so a secret is a binding whose value may not be published and a variable is one whose value may; canon carries exactly that boolean (`masked`) and this row is the same read with a different filter. The `agents` family is canon's `coding-agent` audience; the repository scope's own 32 public-key bytes", mode_reviewed: "2026-09-12", category: "agents", subcategory: "secrets", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/agents/variables", area: "agents", tier: 3, status: "green", mode: "empty", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a) as GitHub's empty envelope at 200: this organization hands its coding agent ONE setting at the REPOSITORY scope and it is a SECRET - the push token the agent runs with - so there is no repository-scoped variable to publish. The one published agent setting, the workspace it operates in, is ORGANIZATION-scoped and reaches this repository through `/repos/{owner}/{repo}/agents/organization-variables`, which is green; duplicating it here would publish one setting as two. The route is the SAME code as its `actions` twin, so the day canon gives the agent a repository variable this row stops being empty on its own, and conformance drives it (`expectsEmpty`) rather than asserting nothing", mode_reviewed: "2026-09-12", category: "agents", subcategory: "variables", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/agents/variables/{name}", area: "agents", tier: 3, status: "deferred", mode: "refuse", mode_reason: "REFUSED 2026-09-12 (hello-19 wave W-a) with GitHub's own 404: no name resolves over the empty collection its list half answers - see that row. Ungated across generations, because \"this repository holds no coding-agent variable\" is as true on all 127 registered pins as it is on hello-19", mode_reviewed: "2026-09-12", category: "agents", subcategory: "variables", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/assignees", area: "issues", tier: 1, status: "green", mode: "derive", mode_reason: "assignable users are the repo's collaborators; assignment is already on the issue", category: "issues", subcategory: "assignees" }
      - { method: "GET", path: "/repos/{owner}/{repo}/assignees/{assignee}", area: "issues", tier: 1, status: "green", mode: "derive", mode_reason: "assignable users are the repo's collaborators; assignment is already on the issue", category: "issues", subcategory: "assignees" }
      - { method: "GET", path: "/repos/{owner}/{repo}/attestations/{subject_digest}", area: "attestations", tier: 3, status: "green", mode: "empty", mode_reason: "no artifact in this universe is attested — all 392 `artifact` rows are plain workflow-run uploads with no provenance bundle and none of the three workflows (`ci`, `lint`, `release`) runs an attestation step; GitHub's own answer for a subject digest with no attestations is `{attestations: []}` at 200 (the spec's 200 has NO required member). The operation also declares a 404 and the ORCHESTRATOR RULED the 200: a digest is a content address rather than a resource id, so asking about an artifact nobody signed is a well-formed question whose answer is \"none\". RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", category: "repos", subcategory: "attestations" }
      - { method: "GET", path: "/repos/{owner}/{repo}/autolinks", area: "autolinks", tier: 3, status: "planned", mode: "generate", mode_reason: "new canon entity Autolink", category: "repos", subcategory: "autolinks" }
      - { method: "GET", path: "/repos/{owner}/{repo}/autolinks/{autolink_id}", area: "autolinks", tier: 3, status: "planned", mode: "generate", mode_reason: "new canon entity Autolink", category: "repos", subcategory: "autolinks" }
      - { method: "GET", path: "/repos/{owner}/{repo}/automated-security-fixes", area: "repos", tier: 1, status: "planned", mode: "refuse", mode_reason: "no GitHub security product is enabled on olympus-labs/parthenon — canon carries no security-finding entity and no code-security configuration, and the org's only repository is private; GitHub's own answer for a repository not enabled with vulnerability alerts is 404 with no body (the spec declares only 204 and 404 for this operation). RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", category: "repos", subcategory: "repos" }
      - { method: "GET", path: "/repos/{owner}/{repo}/branches", area: "repos", tier: 1, status: "green", mode: "derive", category: "branches", subcategory: "branches" }
      - { method: "GET", path: "/repos/{owner}/{repo}/branches/{branch}", area: "repos", tier: 1, status: "green", mode: "derive", category: "branches", subcategory: "branches" }
      - { method: "GET", path: "/repos/{owner}/{repo}/branches/{branch}/protection", area: "protected-branches", tier: 2, status: "green", mode: "derive", category: "branches", subcategory: "branch-protection" }
      - { method: "GET", path: "/repos/{owner}/{repo}/branches/{branch}/protection/enforce_admins", area: "protected-branches", tier: 2, status: "green", mode: "derive", category: "branches", subcategory: "branch-protection" }
      - { method: "GET", path: "/repos/{owner}/{repo}/branches/{branch}/protection/required_pull_request_reviews", area: "protected-branches", tier: 2, status: "green", mode: "derive", category: "branches", subcategory: "branch-protection" }
      - { method: "GET", path: "/repos/{owner}/{repo}/branches/{branch}/protection/required_signatures", area: "protected-branches", tier: 2, status: "green", mode: "derive", mode_reason: "the protection document already shapes required_signatures and the status-check contexts from real check runs (render-protection.ts)", category: "branches", subcategory: "branch-protection" }
      - { method: "GET", path: "/repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks", area: "protected-branches", tier: 2, status: "green", mode: "derive", category: "branches", subcategory: "branch-protection" }
      - { method: "GET", path: "/repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks/contexts", area: "protected-branches", tier: 2, status: "green", mode: "derive", mode_reason: "the protection document already shapes required_signatures and the status-check contexts from real check runs (render-protection.ts)", category: "branches", subcategory: "branch-protection" }
      - { method: "GET", path: "/repos/{owner}/{repo}/branches/{branch}/protection/restrictions", area: "protected-branches", tier: 2, status: "planned", mode: "refuse", mode_reason: "no branch in this repository restricts who may push — canon's only two `protected_ref` rows are scoped to `namespace-001` and repo-01 carries an empty `namespace` column, so the document shapeBranchProtection publishes (render-protection.ts:37) has no `restrictions` object; GitHub's own answer for a protected branch with no push restrictions is 404. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", category: "branches", subcategory: "branch-protection" }
      - { method: "GET", path: "/repos/{owner}/{repo}/branches/{branch}/protection/restrictions/apps", area: "protected-branches", tier: 2, status: "planned", mode: "refuse", mode_reason: "no branch in this repository restricts who may push — canon's only two `protected_ref` rows are scoped to `namespace-001` and repo-01 carries an empty `namespace` column, so the document shapeBranchProtection publishes (render-protection.ts:37) has no `restrictions` object; GitHub's own answer for a protected branch with no push restrictions is 404. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", category: "branches", subcategory: "branch-protection" }
      - { method: "GET", path: "/repos/{owner}/{repo}/branches/{branch}/protection/restrictions/teams", area: "protected-branches", tier: 2, status: "planned", mode: "refuse", mode_reason: "no branch in this repository restricts who may push — canon's only two `protected_ref` rows are scoped to `namespace-001` and repo-01 carries an empty `namespace` column, so the document shapeBranchProtection publishes (render-protection.ts:37) has no `restrictions` object; GitHub's own answer for a protected branch with no push restrictions is 404. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", category: "branches", subcategory: "branch-protection" }
      - { method: "GET", path: "/repos/{owner}/{repo}/branches/{branch}/protection/restrictions/users", area: "protected-branches", tier: 2, status: "planned", mode: "refuse", mode_reason: "no branch in this repository restricts who may push — canon's only two `protected_ref` rows are scoped to `namespace-001` and repo-01 carries an empty `namespace` column, so the document shapeBranchProtection publishes (render-protection.ts:37) has no `restrictions` object; GitHub's own answer for a protected branch with no push restrictions is 404. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", category: "branches", subcategory: "branch-protection" }
      - { method: "GET", path: "/repos/{owner}/{repo}/check-runs/{check_run_id}", area: "checks", tier: 1, status: "green", mode: "derive", category: "checks", subcategory: "runs" }
      - { method: "GET", path: "/repos/{owner}/{repo}/check-runs/{check_run_id}/annotations", area: "checks", tier: 1, status: "green", mode: "empty", mode_reason: "this universe's CI records a per-job conclusion and nothing finer, so a resolving check-run id answers 200 [] while a bogus one still 404s (DECISIONS 2026-08-20 [commit-detail], verdict b)", mode_reviewed: "2026-08-20", category: "checks", subcategory: "runs" }
      - { method: "GET", path: "/repos/{owner}/{repo}/check-suites/{check_suite_id}", area: "checks", tier: 1, status: "green", mode: "derive", category: "checks", subcategory: "suites" }
      - { method: "GET", path: "/repos/{owner}/{repo}/check-suites/{check_suite_id}/check-runs", area: "checks", tier: 1, status: "green", mode: "derive", category: "checks", subcategory: "runs" }
      - { method: "GET", path: "/repos/{owner}/{repo}/code-quality/findings", area: "code-quality", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityFinding", category: "code-quality", subcategory: "code-quality", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/code-quality/findings/{finding_number}", area: "code-quality", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityFinding", category: "code-quality", subcategory: "code-quality", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/code-quality/setup", area: "code-quality", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityFinding", category: "code-quality", subcategory: "code-quality", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/code-scanning/alerts", area: "code-scanning", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityFinding", category: "code-scanning", subcategory: "code-scanning" }
      - { method: "GET", path: "/repos/{owner}/{repo}/code-scanning/alerts/{alert_number}", area: "code-scanning", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityFinding", category: "code-scanning", subcategory: "code-scanning" }
      - { method: "GET", path: "/repos/{owner}/{repo}/code-scanning/alerts/{alert_number}/autofix", area: "code-scanning", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityFinding", category: "code-scanning", subcategory: "code-scanning" }
      - { method: "GET", path: "/repos/{owner}/{repo}/code-scanning/alerts/{alert_number}/instances", area: "code-scanning", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityFinding", category: "code-scanning", subcategory: "code-scanning" }
      - { method: "GET", path: "/repos/{owner}/{repo}/code-scanning/analyses", area: "code-scanning", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityFinding", category: "code-scanning", subcategory: "code-scanning" }
      - { method: "GET", path: "/repos/{owner}/{repo}/code-scanning/analyses/{analysis_id}", area: "code-scanning", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityFinding", category: "code-scanning", subcategory: "code-scanning" }
      - { method: "GET", path: "/repos/{owner}/{repo}/code-scanning/codeql/databases", area: "code-scanning", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityFinding", category: "code-scanning", subcategory: "code-scanning" }
      - { method: "GET", path: "/repos/{owner}/{repo}/code-scanning/codeql/databases/{language}", area: "code-scanning", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityFinding", category: "code-scanning", subcategory: "code-scanning" }
      - { method: "GET", path: "/repos/{owner}/{repo}/code-scanning/codeql/variant-analyses/{codeql_variant_analysis_id}", area: "code-scanning", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityFinding", category: "code-scanning", subcategory: "code-scanning" }
      - { method: "GET", path: "/repos/{owner}/{repo}/code-scanning/codeql/variant-analyses/{codeql_variant_analysis_id}/repos/{repo_owner}/{repo_name}", area: "code-scanning", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityFinding", category: "code-scanning", subcategory: "code-scanning" }
      - { method: "GET", path: "/repos/{owner}/{repo}/code-scanning/default-setup", area: "code-scanning", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityFinding", category: "code-scanning", subcategory: "code-scanning" }
      - { method: "GET", path: "/repos/{owner}/{repo}/code-scanning/sarifs/{sarif_id}", area: "code-scanning", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityFinding", category: "code-scanning", subcategory: "code-scanning" }
      - { method: "GET", path: "/repos/{owner}/{repo}/code-security-configuration", area: "code-security", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityConfiguration", category: "code-security", subcategory: "configurations", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/codeowners/errors", area: "repos", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17 `repoOwnership`): {errors: []} for a file that EXISTS and PARSES. hello-17 puts .github/CODEOWNERS in the tree (decisions/2026-09-11-2256 — one line per subsystem naming the team the service catalogue says is paged for it, at GitHub's own canonical location, which is also the cheapest placement in a content-addressed tree). THE FILE IS PARSED, NOT ASSUMED: packages/renderer-github/src/render-codeowners.ts reads the blob and checks the two things this artifact can ground — an owner token that is not @login, @org/team or an address is GitHub's `Invalid owner`, and one that names no team, login or address this host carries is its `Unknown owner` — and emits nothing else, because inventing GitHub's wording for a rule we cannot evaluate would be a placeholder wearing an error's clothes. A hard-coded empty array would assert the file parses without ever opening it, so conformance re-reads the blob, asserts it carries rules, resolves every @org/team against /orgs/{org}/teams and asserts every owned path prefix has files under it. On an artifact whose tree carries no CODEOWNERS the row answers the hello-17 generation gap rather than GitHub's 404, because a repository without the file and a universe that predates it deserve different sentences (noRepoLicense's argument one generation on)", mode_reviewed: "2026-09-12", category: "repos", subcategory: "repos" }
      - { method: "GET", path: "/repos/{owner}/{repo}/codespaces", area: "codespaces", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no persona in this universe launches a Codespace: every Codespaces object exists only because a write created one, and this universe accepts no writes", mode_reviewed: "2026-09-01", category: "codespaces", subcategory: "codespaces", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/codespaces/devcontainers", area: "codespaces", tier: 3, status: "green", mode: "empty", mode_reason: "no repository in this universe carries a `.devcontainer`, so the repo's devcontainer list is truthfully empty", mode_reviewed: "2026-09-01", category: "codespaces", subcategory: "codespaces", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/codespaces/machines", area: "codespaces", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity CodespacesConfig", category: "codespaces", subcategory: "machines", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/codespaces/new", area: "codespaces", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity CodespacesConfig", category: "codespaces", subcategory: "codespaces", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/codespaces/permissions_check", area: "codespaces", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity CodespacesConfig", category: "codespaces", subcategory: "codespaces", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/codespaces/secrets", area: "codespaces", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no persona in this universe launches a Codespace: every Codespaces object exists only because a write created one, and this universe accepts no writes", mode_reviewed: "2026-09-01", category: "codespaces", subcategory: "repository-secrets", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/codespaces/secrets/{secret_name}", area: "codespaces", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no persona in this universe launches a Codespace: every Codespaces object exists only because a write created one, and this universe accepts no writes", mode_reviewed: "2026-09-01", category: "codespaces", subcategory: "repository-secrets", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/codespaces/secrets/public-key", area: "codespaces", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no persona in this universe launches a Codespace: every Codespaces object exists only because a write created one, and this universe accepts no writes", mode_reviewed: "2026-09-01", category: "codespaces", subcategory: "repository-secrets", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/collaborators", area: "repos", tier: 1, status: "green", mode: "derive", mode_reason: "repo collaborators are the teams with access plus the outside contributors canon already marks (Person.member = false)", category: "collaborators", subcategory: "collaborators" }
      - { method: "GET", path: "/repos/{owner}/{repo}/collaborators/{username}", area: "repos", tier: 1, status: "green", mode: "derive", mode_reason: "repo collaborators are the teams with access plus the outside contributors canon already marks (Person.member = false)", category: "collaborators", subcategory: "collaborators" }
      - { method: "GET", path: "/repos/{owner}/{repo}/collaborators/{username}/permission", area: "repos", tier: 1, status: "green", mode: "derive", mode_reason: "repo collaborators are the teams with access plus the outside contributors canon already marks (Person.member = false)", category: "collaborators", subcategory: "collaborators" }
      - { method: "GET", path: "/repos/{owner}/{repo}/comments", area: "commit-comments", tier: 3, status: "green", mode: "empty", mode_reason: "no commit in this universe carries a comment (DECISIONS 2026-08-20 [commit-detail] decision 2), so the repository-wide commit-comment list is truthfully empty", mode_reviewed: "2026-09-01", category: "commits", subcategory: "comments" }
      - { method: "GET", path: "/repos/{owner}/{repo}/comments/{comment_id}", area: "commit-comments", tier: 3, status: "planned", mode: "refuse", mode_reason: "the id half of the commit-comment pair: with no commit comment in this universe, no comment id can resolve", mode_reviewed: "2026-09-01", category: "commits", subcategory: "comments" }
      - { method: "GET", path: "/repos/{owner}/{repo}/comments/{comment_id}/reactions", area: "reactions", tier: 2, status: "deferred", mode: "refuse", mode_reason: "no commit in this universe carries a comment (DECISIONS 2026-08-20 [commit-detail] decision 2; `/repos/{owner}/{repo}/comments` is already an armed honest empty in honest-empties.ts), so no `comment_id` can ever resolve and GitHub's own answer for a commit comment that does not exist is 404 — the row waits on a CommitComment, not on ContentReaction, whose 80 rows already answer GitHub's other four reaction operations. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", category: "reactions", subcategory: "reactions" }
      - { method: "GET", path: "/repos/{owner}/{repo}/commits", area: "repos", tier: 1, status: "green", mode: "derive", category: "commits", subcategory: "commits" }
      - { method: "GET", path: "/repos/{owner}/{repo}/commits/{commit_sha}/branches-where-head", area: "repos", tier: 1, status: "green", mode: "derive", category: "commits", subcategory: "commits" }
      - { method: "GET", path: "/repos/{owner}/{repo}/commits/{commit_sha}/comments", area: "commit-comments", tier: 3, status: "green", mode: "empty", mode_reason: "no commit in this universe carries a comment: review conversation happens on the pull request, and canon has no commit-comment entity (DECISIONS 2026-08-20 [commit-detail] decision 2)", mode_reviewed: "2026-08-20", category: "commits", subcategory: "comments" }
      - { method: "GET", path: "/repos/{owner}/{repo}/commits/{commit_sha}/pulls", area: "repos", tier: 1, status: "green", mode: "derive", category: "commits", subcategory: "commits" }
      - { method: "GET", path: "/repos/{owner}/{repo}/commits/{ref}", area: "repos", tier: 1, status: "green", mode: "derive", category: "commits", subcategory: "commits" }
      - { method: "GET", path: "/repos/{owner}/{repo}/commits/{ref}/check-runs", area: "checks", tier: 1, status: "green", mode: "derive", category: "checks", subcategory: "runs" }
      - { method: "GET", path: "/repos/{owner}/{repo}/commits/{ref}/check-suites", area: "checks", tier: 1, status: "green", mode: "derive", category: "checks", subcategory: "suites" }
      - { method: "GET", path: "/repos/{owner}/{repo}/commits/{ref}/status", area: "commit-statuses", tier: 1, status: "green", mode: "derive", category: "commits", subcategory: "statuses" }
      - { method: "GET", path: "/repos/{owner}/{repo}/commits/{ref}/statuses", area: "commit-statuses", tier: 1, status: "green", mode: "derive", category: "commits", subcategory: "statuses" }
      - { method: "GET", path: "/repos/{owner}/{repo}/community/profile", area: "metrics", tier: 3, status: "green", mode: "derive", mode_reason: "the community profile is which of README/LICENSE/CONTRIBUTING/CODE_OF_CONDUCT the tree actually holds", category: "metrics", subcategory: "community", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/compare/{basehead}", area: "repos", tier: 1, status: "green", mode: "derive", category: "commits", subcategory: "commits" }
      - { method: "GET", path: "/repos/{owner}/{repo}/contents/{path}", area: "repos", tier: 1, status: "green", mode: "derive", category: "repos", subcategory: "contents" }
      - { method: "GET", path: "/repos/{owner}/{repo}/contributors", area: "repos", tier: 1, status: "green", mode: "derive", category: "repos", subcategory: "repos" }
      - { method: "GET", path: "/repos/{owner}/{repo}/copilot/cloud-agent/configuration", area: "copilot", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity CopilotPolicy", category: "copilot", subcategory: "copilot-cloud-agent-management" }
      - { method: "GET", path: "/repos/{owner}/{repo}/dependabot/alerts", area: "dependabot", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityFinding", category: "dependabot", subcategory: "alerts" }
      - { method: "GET", path: "/repos/{owner}/{repo}/dependabot/alerts/{alert_number}", area: "dependabot", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityFinding", category: "dependabot", subcategory: "alerts" }
      - { method: "GET", path: "/repos/{owner}/{repo}/dependabot/secrets", area: "dependabot", tier: 3, status: "green", mode: "empty", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a) as GitHub's empty envelope at 200, by FOUNDER RULING F3 (2026-09-12): olympus-labs runs no private package registry, so a dependency bot has nothing private to reach and this repository holds no Dependabot secret. The SCOPE is real - canon mints it and `.../dependabot/secrets/public-key` is green beside this row, exactly as GitHub publishes a Dependabot public key whether or not a secret exists - and the empty list is only an honest `[]` once something says the scope exists, which is why this row is gated on `hasCiBindings()` and answers the generation on an older artifact. `compiler/src/hello19.test.ts` coherence check 9 asserts the emptiness in canon at both windows, so the ruling is falsifiable the day this organization gains a private registry", mode_reviewed: "2026-09-12", category: "dependabot", subcategory: "secrets" }
      - { method: "GET", path: "/repos/{owner}/{repo}/dependabot/secrets/{secret_name}", area: "dependabot", tier: 3, status: "deferred", mode: "refuse", mode_reason: "REFUSED 2026-09-12 (hello-19 wave W-a) with GitHub's own 404: no name resolves over the empty collection founder ruling F3 leaves at this scope", mode_reviewed: "2026-09-12", category: "dependabot", subcategory: "secrets" }
      - { method: "GET", path: "/repos/{owner}/{repo}/dependabot/secrets/public-key", area: "dependabot", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` + `ci_binding_scope` - the settings and credentials this organization hands its pipelines. GitHub publishes ONE object as two URL families, so a secret is a binding whose value may not be published and a variable is one whose value may; canon carries exactly that boolean (`masked`) and this row is the same read with a different filter. The Dependabot scope's own 32 X25519 public-key bytes. GREEN even though the collection beside it is empty by founder ruling F3, because that is exactly what GitHub does: the key is what a client would encrypt a NEW secret to, so it is published whether or not one exists", mode_reviewed: "2026-09-12", category: "dependabot", subcategory: "secrets" }
      - { method: "GET", path: "/repos/{owner}/{repo}/dependency-graph/compare/{basehead}", area: "dependency-graph", tier: 3, status: "green", mode: "empty", mode_reason: "THE MANIFESTS NEVER CHANGE BETWEEN COMMITS. hello-9's scaffold writes package.json, pnpm-lock.yaml, go.mod/go.sum and requirements.txt from constants, so every commit in a repository carries byte-identical dependency declarations and the diff between any two refs is genuinely empty — GitHub returns the same `[]` for a comparison that adds and removes nothing. This is not the SBOM being unavailable: `/dependency-graph/sbom` serves the real package list (#418), and this row says only that the list did not MOVE. Falsifiable: the day the generator varies a manifest across commits, a comparison spanning that change stops being empty and the row goes red. RULED by the founder 2026-09-09", mode_reviewed: "2026-09-09", category: "dependency-graph", subcategory: "dependency-review", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/dependency-graph/sbom", area: "dependency-graph", tier: 3, status: "green", mode: "derive", mode_reason: "the SBOM is the repo's own manifests and lockfiles, which hello-9 generates for real (DECISIONS 2026-08-22 [compiler/gen-9])", category: "dependency-graph", subcategory: "sboms", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/dependency-graph/sbom/fetch-report/{sbom_uuid}", area: "dependency-graph", tier: 3, status: "deferred", mode: "generate", mode_reason: "needs a gateway download route (service-own endpoint) — later. The DATA is already served: `/dependency-graph/sbom` returns the real SPDX document (#418). This pair is the request-then-download flow, and its second half is a 302 to bytes on the SERVICE host, so it needs a route in packages/gateway rather than more renderer. Minting an `sbom_url` that 404s would be a placeholder link (invariant #4). RULED by the founder 2026-09-09", mode_reviewed: "2026-09-09", category: "dependency-graph", subcategory: "sboms", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/dependency-graph/sbom/generate-report", area: "dependency-graph", tier: 3, status: "deferred", mode: "generate", mode_reason: "needs a gateway download route (service-own endpoint) — later. The DATA is already served: `/dependency-graph/sbom` returns the real SPDX document (#418). This row's 201 hands back an `sbom_url` the fetch-report row must then serve, so the two land together or neither does. RULED by the founder 2026-09-09", mode_reviewed: "2026-09-09", category: "dependency-graph", subcategory: "sboms", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/deployments", area: "deployments", tier: 2, status: "green", mode: "derive", category: "deployments", subcategory: "deployments" }
      - { method: "GET", path: "/repos/{owner}/{repo}/deployments/{deployment_id}", area: "deployments", tier: 2, status: "green", mode: "derive", category: "deployments", subcategory: "deployments" }
      - { method: "GET", path: "/repos/{owner}/{repo}/deployments/{deployment_id}/statuses", area: "deployments", tier: 2, status: "green", mode: "derive", category: "deployments", subcategory: "statuses" }
      - { method: "GET", path: "/repos/{owner}/{repo}/deployments/{deployment_id}/statuses/{status_id}", area: "deployments", tier: 2, status: "green", mode: "derive", category: "deployments", subcategory: "statuses" }
      - { method: "GET", path: "/repos/{owner}/{repo}/environments", area: "deployments", tier: 2, status: "green", mode: "derive", category: "deployments", subcategory: "environments" }
      - { method: "GET", path: "/repos/{owner}/{repo}/environments/{environment_name}", area: "deployments", tier: 2, status: "green", mode: "derive", category: "deployments", subcategory: "environments" }
      - { method: "GET", path: "/repos/{owner}/{repo}/environments/{environment_name}/deployment_protection_rules", area: "deployments", tier: 2, status: "green", mode: "empty", mode_reason: "neither `production` nor `staging` restricts which branches may deploy to it — all 22 `deployment` rows name a ref that already exists in `branch`, and canon carries no per-environment branch policy; GitHub's own answer for an environment with no policies is `{total_count: 0, branch_policies: []}` at 200 (this operation nests the same empty page under `custom_deployment_protection_rules`). RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", category: "deployments", subcategory: "protection-rules" }
      - { method: "GET", path: "/repos/{owner}/{repo}/environments/{environment_name}/deployment_protection_rules/{protection_rule_id}", area: "deployments", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity EnvironmentProtectionRule", category: "deployments", subcategory: "protection-rules" }
      - { method: "GET", path: "/repos/{owner}/{repo}/environments/{environment_name}/deployment_protection_rules/apps", area: "deployments", tier: 2, status: "green", mode: "empty", mode_reason: "neither `production` nor `staging` restricts which branches may deploy to it — all 22 `deployment` rows name a ref that already exists in `branch`, and canon carries no per-environment branch policy; GitHub's own answer for an environment with no policies is `{total_count: 0, branch_policies: []}` at 200 (this operation nests the same empty page under `available_custom_deployment_protection_rule_integrations`). RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", category: "deployments", subcategory: "protection-rules" }
      - { method: "GET", path: "/repos/{owner}/{repo}/environments/{environment_name}/deployment-branch-policies", area: "deployments", tier: 2, status: "green", mode: "empty", mode_reason: "neither `production` nor `staging` restricts which branches may deploy to it — all 22 `deployment` rows name a ref that already exists in `branch`, and canon carries no per-environment branch policy; GitHub's own answer for an environment with no policies is `{total_count: 0, branch_policies: []}` at 200 (this operation nests the same empty page under `branch_policies`). RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", category: "deployments", subcategory: "branch-policies" }
      - { method: "GET", path: "/repos/{owner}/{repo}/environments/{environment_name}/deployment-branch-policies/{branch_policy_id}", area: "deployments", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity EnvironmentProtectionRule", category: "deployments", subcategory: "branch-policies" }
      - { method: "GET", path: "/repos/{owner}/{repo}/environments/{environment_name}/secrets", area: "actions", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` + `ci_binding_scope` - the settings and credentials this organization hands its pipelines. GitHub publishes ONE object as two URL families, so a secret is a binding whose value may not be published and a variable is one whose value may; canon carries exactly that boolean (`masked`) and this row is the same read with a different filter. One scope per name `deployment.environment` actually carries, dated to the FIRST deployment to it. The environment has to resolve through the same derivation `/environments` publishes, so one named there is one this row answers for and one that is not is the ordinary 404", mode_reviewed: "2026-09-12", category: "actions", subcategory: "secrets" }
      - { method: "GET", path: "/repos/{owner}/{repo}/environments/{environment_name}/secrets/{secret_name}", area: "actions", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` + `ci_binding_scope` - the settings and credentials this organization hands its pipelines. GitHub publishes ONE object as two URL families, so a secret is a binding whose value may not be published and a variable is one whose value may; canon carries exactly that boolean (`masked`) and this row is the same read with a different filter. A name the list published", mode_reviewed: "2026-09-12", category: "actions", subcategory: "secrets" }
      - { method: "GET", path: "/repos/{owner}/{repo}/environments/{environment_name}/secrets/public-key", area: "actions", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` + `ci_binding_scope` - the settings and credentials this organization hands its pipelines. GitHub publishes ONE object as two URL families, so a secret is a binding whose value may not be published and a variable is one whose value may; canon carries exactly that boolean (`masked`) and this row is the same read with a different filter. The environment scope's own 32 public-key bytes", mode_reviewed: "2026-09-12", category: "actions", subcategory: "secrets" }
      - { method: "GET", path: "/repos/{owner}/{repo}/environments/{environment_name}/variables", area: "actions", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` + `ci_binding_scope` - the settings and credentials this organization hands its pipelines. GitHub publishes ONE object as two URL families, so a secret is a binding whose value may not be published and a variable is one whose value may; canon carries exactly that boolean (`masked`) and this row is the same read with a different filter. The environment's own name, published - and READ from the scope's `environment` column, which is a name copied out of the deployments rather than authored, so the two surfaces cannot name the environment two different things", mode_reviewed: "2026-09-12", category: "actions", subcategory: "variables" }
      - { method: "GET", path: "/repos/{owner}/{repo}/environments/{environment_name}/variables/{name}", area: "actions", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` + `ci_binding_scope` - the settings and credentials this organization hands its pipelines. GitHub publishes ONE object as two URL families, so a secret is a binding whose value may not be published and a variable is one whose value may; canon carries exactly that boolean (`masked`) and this row is the same read with a different filter. A name the list published", mode_reviewed: "2026-09-12", category: "actions", subcategory: "variables" }
      - { method: "GET", path: "/repos/{owner}/{repo}/events", area: "events-timeline", tier: 2, status: "green", mode: "derive", category: "activity", subcategory: "events" }
      - { method: "GET", path: "/repos/{owner}/{repo}/forks", area: "repos", tier: 1, status: "green", mode: "empty", mode_reason: "no repository in this universe is a fork and none has been forked: the org owns every repo and there is no account outside it to fork into", mode_reviewed: "2026-09-01", category: "repos", subcategory: "forks" }
      - { method: "GET", path: "/repos/{owner}/{repo}/git/blobs/{file_sha}", area: "git-data", tier: 3, status: "green", mode: "derive", category: "git", subcategory: "blobs" }
      - { method: "GET", path: "/repos/{owner}/{repo}/git/commits/{commit_sha}", area: "git-data", tier: 3, status: "green", mode: "derive", category: "git", subcategory: "commits" }
      - { method: "GET", path: "/repos/{owner}/{repo}/git/matching-refs/{ref}", area: "git-data", tier: 3, status: "green", mode: "derive", mode_reason: "refs resolve against the branch/commit tables the git transport already serves", category: "git", subcategory: "refs" }
      - { method: "GET", path: "/repos/{owner}/{repo}/git/ref/{ref}", area: "git-data", tier: 3, status: "green", mode: "derive", mode_reason: "refs resolve against the branch/commit tables the git transport already serves", category: "git", subcategory: "refs" }
      - { method: "GET", path: "/repos/{owner}/{repo}/git/tags/{tag_sha}", area: "git-data", tier: 3, status: "deferred", mode: "refuse", mode_reason: "EVERY TAG IN THIS UNIVERSE IS LIGHTWEIGHT. A canonical `release` carries tag, body, author, created_epoch and tag_commit, but no tag OBJECT and therefore no object sha — and `{tag_sha}` is the only way this operation is addressed, so no sha can ever resolve. The project already ruled this in packages/renderer-github/src/git/objects.ts (`repoRefs`): 'Tags are LIGHTWEIGHT (a ref straight at a commit), which is what the artifact actually models … Inventing an annotated tag object here would mint a sha no other endpoint serves.' The Azure DevOps twin (`.../annotatedtags/{objectId}`) was ruled the same way in #419. GitHub answers 404 for a git object it does not hold, which is the whole answer. RULED by the founder 2026-09-09", mode_reviewed: "2026-09-09", category: "git", subcategory: "tags" }
      - { method: "GET", path: "/repos/{owner}/{repo}/git/trees/{tree_sha}", area: "git-data", tier: 3, status: "green", mode: "derive", category: "git", subcategory: "trees" }
      - { method: "GET", path: "/repos/{owner}/{repo}/hash-algorithm", area: "repos", tier: 1, status: "green", mode: "derive", category: "repos", subcategory: "repos" }
      - { method: "GET", path: "/repos/{owner}/{repo}/hooks", area: "webhooks-config", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-18 serving wave W-c): off `webhook_subscription`'s hello-18 git-host scopes (features.webhookFilters) through reader.repoWebhooks(), gated on hasWebhookFilters() so hello-17 and all eighty-one -g8..-g11 pins name the generation instead of claiming this organization configured no webhook. Canon stores NEUTRAL event names and this renderer spells them GitHub's way - ref.pushed->push, change.opened/change.merged->pull_request, issue.opened/issue.closed->issues, build.completed->check_run - many-to-one because GitHub subscribes by event NAME and puts the verb in the payload's `action`. The repository object has advertised `hooks_url` since wave A and it finally resolves; conformance walks the page and asserts it.", mode_reviewed: "2026-09-12", category: "repos", subcategory: "webhooks" }
      - { method: "GET", path: "/repos/{owner}/{repo}/hooks/{hook_id}", area: "webhooks-config", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-18 serving wave W-c): off `webhook_subscription`'s hello-18 git-host scopes (features.webhookFilters) through reader.repoWebhooks(), gated on hasWebhookFilters() so hello-17 and all eighty-one -g8..-g11 pins name the generation instead of claiming this organization configured no webhook. Canon stores NEUTRAL event names and this renderer spells them GitHub's way - ref.pushed->push, change.opened/change.merged->pull_request, issue.opened/issue.closed->issues, build.completed->check_run - many-to-one because GitHub subscribes by event NAME and puts the verb in the payload's `action`. Byte-identical to the object the list publishes - one shaper - and the ORGANIZATION's hook id 404s here, which is the scope separation reader.repoWebhooks() enforces one layer down.", mode_reviewed: "2026-09-12", category: "repos", subcategory: "webhooks" }
      - { method: "GET", path: "/repos/{owner}/{repo}/hooks/{hook_id}/config", area: "webhooks-config", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-18 serving wave W-c): off `webhook_subscription`'s hello-18 git-host scopes (features.webhookFilters) through reader.repoWebhooks(), gated on hasWebhookFilters() so hello-17 and all eighty-one -g8..-g11 pins name the generation instead of claiming this organization configured no webhook. Canon stores NEUTRAL event names and this renderer spells them GitHub's way - ref.pushed->push, change.opened/change.merged->pull_request, issue.opened/issue.closed->issues, build.completed->check_run - many-to-one because GitHub subscribes by event NAME and puts the verb in the payload's `action`. `config` is the same object the hook embeds: url is the delivery_url column, insecure_ssl is READ OFF that URL's scheme, secret is GitHub's own eight-asterisk redaction (the renderer-circleci signing_secret precedent - canon stores no secret because every host redacts it), and content_type is json because these receivers are the org's own ReceiverSlots, into which PagerDuty and CircleCI already deliver JSON and can deliver nothing else.", mode_reviewed: "2026-09-12", category: "repos", subcategory: "webhooks" }
      - { method: "GET", path: "/repos/{owner}/{repo}/hooks/{hook_id}/deliveries", area: "webhooks-config", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Webhook", category: "repos", subcategory: "webhooks" }
      - { method: "GET", path: "/repos/{owner}/{repo}/hooks/{hook_id}/deliveries/{delivery_id}", area: "webhooks-config", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Webhook", category: "repos", subcategory: "webhooks" }
      - { method: "GET", path: "/repos/{owner}/{repo}/immutable-releases", area: "repos", tier: 1, status: "planned", mode: "refuse", mode_reason: "immutable releases are not enabled on olympus-labs/parthenon — its three `release` rows carry no immutability marker and canon has no repository release-immutability setting; GitHub's own answer for a repository where immutable releases are not enabled is 404 with no body (the spec's own 404 description). The renderer answers the `basic-error` body every GitHub 404 on this host carries, pointing at THIS operation's docs page: the spec declares no schema for the 404, and GitHub's API never sends a bodyless one. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", category: "repos", subcategory: "repos" }
      - { method: "GET", path: "/repos/{owner}/{repo}/import", area: "migrations", tier: 3, status: "retired", mode: "refuse", mode_reason: "a source import exists only because someone started one, and this universe has never run one — but GitHub removed the Source Import API on 2024-04-12, before the 2026-03-10 generation every gh pin emulates, so no pin serves it and every host answers GitHub's own deprecated 404 naming the GitHub Importer (meta.retired_meaning)", mode_reviewed: "2026-09-02", category: "migrations", subcategory: "source-imports" }
      - { method: "GET", path: "/repos/{owner}/{repo}/import/authors", area: "migrations", tier: 3, status: "retired", mode: "refuse", mode_reason: "a source import exists only because someone started one, and this universe has never run one — but GitHub removed the Source Import API on 2024-04-12, before the 2026-03-10 generation every gh pin emulates, so no pin serves it and every host answers GitHub's own deprecated 404 naming the GitHub Importer (meta.retired_meaning)", mode_reviewed: "2026-09-02", category: "migrations", subcategory: "source-imports" }
      - { method: "GET", path: "/repos/{owner}/{repo}/import/large_files", area: "migrations", tier: 3, status: "retired", mode: "refuse", mode_reason: "a source import exists only because someone started one, and this universe has never run one — but GitHub removed the Source Import API on 2024-04-12, before the 2026-03-10 generation every gh pin emulates, so no pin serves it and every host answers GitHub's own deprecated 404 naming the GitHub Importer (meta.retired_meaning)", mode_reviewed: "2026-09-02", category: "migrations", subcategory: "source-imports" }
      - { method: "GET", path: "/repos/{owner}/{repo}/installation", area: "apps", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity GitHubApp", category: "apps", subcategory: "apps", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/interaction-limits", area: "interactions", tier: 3, status: "green", mode: "empty", mode_reason: "no interaction limit is active anywhere in this universe — olympus-labs is a private organization whose one repository is private (repo.visibility='private'), so there is no drive-by traffic to limit and nobody has set one; GitHub's own answer for a scope with no active limit is `{}` at 200 (the spec's 200 has no required member). RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", category: "interactions", subcategory: "repos", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/interaction-limits/pulls/bypass-list", area: "interactions", tier: 3, status: "green", mode: "empty", mode_reason: "no interaction limit is active anywhere in this universe — olympus-labs is a private organization whose one repository is private (repo.visibility='private'), so there is no drive-by traffic to limit and nobody has set one; this operation's own 200 is an ARRAY of the users who may bypass the cap, so its empty answer is `[]` rather than the `{}` the three limit reads carry. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", category: "interactions", subcategory: "repos", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/interaction-limits/pulls/creation-cap", area: "interactions", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity InteractionLimit", category: "interactions", subcategory: "repos", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/invitations", area: "repos", tier: 1, status: "green", mode: "empty", mode_reason: "no pending repository invitations in this universe: reader.listMemberships(repo, repo) (reader.ts:2961) holds six rows and every one is `active` — the repository roster is the approvers whose organization role is a plain member, plus the CI identity, and all of them were GRANTED rather than offered. SERVED 2026-09-10 as GitHub's empty array, behind the hello-16 generation gate and behind the repository guard — an unknown repository is still GitHub's own 404 — RULED EMPTY by the founder 2026-09-10", mode_reviewed: "2026-09-10", category: "collaborators", subcategory: "invitations" }
      - { method: "GET", path: "/repos/{owner}/{repo}/issue-types", area: "issue-types", tier: 3, status: "green", mode: "derive", mode_reason: "STALE REASON (\"new canon entity IssueType\"): there is no entity to build. GitHub's issue type is a NAME plus a nullable description, and the set this organization offers IS `select distinct kind from issue` — a closed canon vocabulary (bug, feature-request, incident, question, task) present in every generation. Conformance cross-checks the published list against every issue's kind in BOTH directions, so a type nothing can be and a kind nothing advertises are each red", mode_reviewed: "2026-09-12", category: "repos", subcategory: "issue-types" }
      - { method: "GET", path: "/repos/{owner}/{repo}/issues", area: "issues", tier: 1, status: "green", mode: "derive", category: "issues", subcategory: "issues" }
      - { method: "GET", path: "/repos/{owner}/{repo}/issues/{issue_number}", area: "issues", tier: 1, status: "green", mode: "derive", category: "issues", subcategory: "issues" }
      - { method: "GET", path: "/repos/{owner}/{repo}/issues/{issue_number}/assignees/{assignee}", area: "issues", tier: 1, status: "green", mode: "derive", mode_reason: "assignable users are the repo's collaborators; assignment is already on the issue", category: "issues", subcategory: "assignees" }
      - { method: "GET", path: "/repos/{owner}/{repo}/issues/{issue_number}/comments", area: "issues", tier: 1, status: "green", mode: "derive", category: "issues", subcategory: "comments" }
      - { method: "GET", path: "/repos/{owner}/{repo}/issues/{issue_number}/dependencies/blocked_by", area: "issues", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): reader.linksFor(issue) narrowed to `blocks` rows whose TARGET is this issue — the prerequisites that finished before it started. hello-17 `issueLinks` (decisions/2026-09-11-0200) groups issues by (epic, sprint) — a team's slice of one storyline inside one iteration, the tightest grouping the tracker already holds — and writes ONE row per adjacent pair, whose kind the dates decide: `blocks` when the earlier issue closed strictly before the later one opened, `relates` otherwise. One row per pair is what makes \"no link is its own inverse\" true by construction rather than by a filter, and the direction is read off source/target. Conformance re-derives the canon rule on the wire: every blocker must be closed, and closed strictly before the asking issue was created. A pull-request number carries no dependency and is GitHub's 404, because canon links issues to issues", mode_reviewed: "2026-09-12", category: "issues", subcategory: "issue-dependencies" }
      - { method: "GET", path: "/repos/{owner}/{repo}/issues/{issue_number}/dependencies/blocking", area: "issues", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): the same rows read from the other end — `blocks` links whose SOURCE is this issue. hello-17 `issueLinks` (decisions/2026-09-11-0200) groups issues by (epic, sprint) — a team's slice of one storyline inside one iteration, the tightest grouping the tracker already holds — and writes ONE row per adjacent pair, whose kind the dates decide: `blocks` when the earlier issue closed strictly before the later one opened, `relates` otherwise. One row per pair is what makes \"no link is its own inverse\" true by construction rather than by a filter, and the direction is read off source/target. Conformance asserts the pair agrees: the issue a blocked_by row names must report blocking the issue that named it, which is the one-row-per-pair claim checked from both sides", mode_reviewed: "2026-09-12", category: "issues", subcategory: "issue-dependencies" }
      - { method: "GET", path: "/repos/{owner}/{repo}/issues/{issue_number}/events", area: "issues", tier: 1, status: "green", mode: "derive", category: "issues", subcategory: "events" }
      - { method: "GET", path: "/repos/{owner}/{repo}/issues/{issue_number}/issue-field-values", area: "issues", tier: 1, status: "green", mode: "empty", mode_reason: "olympus-labs defines no issue field — canon's only custom-field table (`custom_field`, 8 rows) is scoped to `incident`, so no issue can carry a value for one; GitHub's own answer for an issue with no field values is `[]` at 200. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", category: "issues", subcategory: "issue-field-values" }
      - { method: "GET", path: "/repos/{owner}/{repo}/issues/{issue_number}/labels", area: "issues", tier: 1, status: "green", mode: "derive", category: "issues", subcategory: "labels" }
      - { method: "GET", path: "/repos/{owner}/{repo}/issues/{issue_number}/parent", area: "issues", tier: 1, status: "planned", mode: "generate", mode_reason: "hello-17's `issueLinks` IS in canon and the two DEPENDENCY rows went `derive` on 2026-09-12 — but this operation asks for an issue's PARENT ISSUE, and canon has no issue-to-issue parentage. Its parentage runs issue.epic -> EpicId and epic.parent -> EpicId, and an Epic is its own entity in its own table, so an issue_link row of kind `parent` would point at an id that does not resolve in the table its column names: invariant #5 broken to fill an enum (decisions/2026-09-11-0200 checked this and ruled it out in as many words). THE ASK: issue-to-issue parentage, i.e. an epic that is also an issue, or a parent column on Issue. `parent` stays in the closed kind vocabulary so the column can say it the day canon can — a closed enum with an unused member is a vocabulary, a ROW with an invented relationship is a placeholder, and only the second is forbidden. Reported by the 2026-09-12 GitHub hello-17 serving wave", mode_reviewed: "2026-09-12", category: "issues", subcategory: "sub-issues" }
      - { method: "GET", path: "/repos/{owner}/{repo}/issues/{issue_number}/reactions", area: "reactions", tier: 2, status: "green", mode: "derive", mode_reason: "ContentReaction is canon as of hello-15 (features.contentReactions); reactionsFor() answers it and shapeReaction renders GitHub's closed eight-value content enum over the SAME rows GitLab serves as award emoji. The parent resources now carry the reaction-rollup GitHub embeds", mode_reviewed: "2026-09-07", category: "reactions", subcategory: "reactions" }
      - { method: "GET", path: "/repos/{owner}/{repo}/issues/{issue_number}/sub_issues", area: "issues", tier: 1, status: "planned", mode: "generate", mode_reason: "hello-17's `issueLinks` IS in canon and the two DEPENDENCY rows went `derive` on 2026-09-12 — but sub-issues are the child half of issue-to-issue parentage, which canon does not have: parentage runs issue.epic -> EpicId, and an Epic is its own entity rather than an issue, so a sub-issue list would either be empty for every issue or would name epics through a column that says `issue`. THE ASK: issue-to-issue parentage. Ruling it `empty` would make a missing relation look like a fact about this organization's tracker, so it answers the honest coverage 404 instead. Reported by the 2026-09-12 GitHub hello-17 serving wave", mode_reviewed: "2026-09-12", category: "issues", subcategory: "sub-issues" }
      - { method: "GET", path: "/repos/{owner}/{repo}/issues/{issue_number}/suggestions", area: "issues", tier: 1, status: "green", mode: "empty", mode_reason: "no issue in this universe carries a Copilot suggestion — canon's AI telemetry attributes work to commits (`ai_commit`, 110), pulls (`ai_pull`, 14) and sessions (`agent_session`, 72) and never to an issue; GitHub's own answer for an issue with no suggestions is `[]` at 200. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", category: "issues", subcategory: "issues" }
      - { method: "GET", path: "/repos/{owner}/{repo}/issues/{issue_number}/timeline", area: "issues", tier: 1, status: "green", mode: "derive", mode_reason: "the timeline is the projection of comments, events, transitions and cross-references canon already carries", category: "issues", subcategory: "timeline" }
      - { method: "GET", path: "/repos/{owner}/{repo}/issues/comments", area: "issues", tier: 1, status: "green", mode: "derive", mode_reason: "repo-wide issue comments over issue_comment (122-hit demand cluster, telemetry 2026-09-01)", category: "issues", subcategory: "comments" }
      - { method: "GET", path: "/repos/{owner}/{repo}/issues/comments/{comment_id}", area: "issues", tier: 1, status: "green", mode: "derive", category: "issues", subcategory: "comments" }
      - { method: "GET", path: "/repos/{owner}/{repo}/issues/comments/{comment_id}/reactions", area: "reactions", tier: 2, status: "green", mode: "derive", mode_reason: "ContentReaction is canon as of hello-15 (features.contentReactions); reactionsFor() answers it and shapeReaction renders GitHub's closed eight-value content enum over the SAME rows GitLab serves as award emoji. The parent resources now carry the reaction-rollup GitHub embeds", mode_reviewed: "2026-09-07", category: "reactions", subcategory: "reactions" }
      - { method: "GET", path: "/repos/{owner}/{repo}/issues/events", area: "issues", tier: 1, status: "green", mode: "derive", mode_reason: "issue events over the canonical event log and issue_transition", category: "issues", subcategory: "events" }
      - { method: "GET", path: "/repos/{owner}/{repo}/issues/events/{event_id}", area: "issues", tier: 1, status: "green", mode: "derive", mode_reason: "issue events over the canonical event log and issue_transition", category: "issues", subcategory: "events" }
      - { method: "GET", path: "/repos/{owner}/{repo}/keys", area: "deploy-keys", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09: reader.listCheckoutKeys(repo) (packages/artifact/src/reader.ts:2351), validated against the vendored `deploy-key` component. packages/canon/src/ci-config.ts:236 names THIS endpoint as the reason a checkout key's public half is publishable at all; `key` is the ssh-ed25519 material and `title` its OpenSSH comment, and the conformance entry re-hashes the decoded blob to the artifact's own fingerprint_sha256. `read_only` is true because a CI checkout key clones, and `last_used` is null because canon records no use. Paginated with GitHub's Link header, walked to the last page in conformance; answers the hello-15 generation gap on an older artifact rather than an empty array", mode_reviewed: "2026-09-09", category: "deploy-keys", subcategory: "deploy-keys", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/keys/{key_id}", area: "deploy-keys", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09: the same key by id — reader.listCheckoutKeys(repo) (packages/artifact/src/reader.ts:2351) addressed by githubId(CheckoutKeyRow.id), byte-identical to the row the list serves. An id nothing holds is GitHub's own 404", mode_reviewed: "2026-09-09", category: "deploy-keys", subcategory: "deploy-keys", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/labels", area: "issues", tier: 1, status: "green", mode: "derive", category: "issues", subcategory: "labels" }
      - { method: "GET", path: "/repos/{owner}/{repo}/labels/{name}", area: "issues", tier: 1, status: "green", mode: "derive", category: "issues", subcategory: "labels" }
      - { method: "GET", path: "/repos/{owner}/{repo}/languages", area: "repos", tier: 1, status: "green", mode: "derive", category: "repos", subcategory: "repos" }
      - { method: "GET", path: "/repos/{owner}/{repo}/license", area: "licenses", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): the LICENSE blob `features.repoLicense` put in every tree, read through the same fileAt/shapeContentFile path /repos/{owner}/{repo}/contents/LICENSE uses, so the two cannot describe different bytes. The `license` object is the one `shapeRepo` has published since Wave A (MIT_LICENSE in packages/renderer-github/src/render.ts), which closes the inconsistency the 2026-09-01 reason named: the repository object and this row can no longer name different licences, and conformance asserts they are byte-identical AND that both match the artifact's own /licenses catalogue row for `mit`. The served body carries no upstream `[year]`/`[fullname]` placeholder. `_links.self`, `_links.git` and `download_url` all resolve on this host — the last over the `/{owner}/{repo}/raw/{ref}/{path}` path this renderer has advertised on every content-file since SPEC rev 7 and now answers. `license.url` still points at the /licenses catalogue, which is the CATALOGUE wave's coverage and answers the honest coverage 404 until it lands. An older artifact answers the hello-16 generation gap rather than GitHub's no-licence 404, which would contradict the `license: MIT` the repository object serves on the same host", mode_reviewed: "2026-09-09", category: "licenses", subcategory: "licenses", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/milestones", area: "issues", tier: 1, status: "green", mode: "derive", category: "issues", subcategory: "milestones" }
      - { method: "GET", path: "/repos/{owner}/{repo}/milestones/{milestone_number}", area: "issues", tier: 1, status: "green", mode: "derive", category: "issues", subcategory: "milestones" }
      - { method: "GET", path: "/repos/{owner}/{repo}/milestones/{milestone_number}/labels", area: "issues", tier: 1, status: "green", mode: "derive", mode_reason: "labels over issue_label/label", category: "issues", subcategory: "labels" }
      - { method: "GET", path: "/repos/{owner}/{repo}/notifications", area: "notifications", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Notification", category: "activity", subcategory: "notifications" }
      - { method: "GET", path: "/repos/{owner}/{repo}/pages", area: "pages", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity PagesSite", category: "pages", subcategory: "pages", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/pages/builds", area: "pages", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity PagesSite", category: "pages", subcategory: "pages", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/pages/builds/{build_id}", area: "pages", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity PagesSite", category: "pages", subcategory: "pages", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/pages/builds/latest", area: "pages", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity PagesSite", category: "pages", subcategory: "pages", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/pages/deployments/{pages_deployment_id}", area: "pages", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity PagesSite", category: "pages", subcategory: "pages", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/pages/health", area: "pages", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity PagesSite", category: "pages", subcategory: "pages", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/private-vulnerability-reporting", area: "repos", tier: 1, status: "planned", mode: "generate", mode_reason: "new canon entity SecurityConfiguration", category: "repos", subcategory: "repos" }
      - { method: "GET", path: "/repos/{owner}/{repo}/properties/values", area: "custom-properties", tier: 3, status: "planned", mode: "generate", mode_reason: "new canon entity CustomProperty", category: "repos", subcategory: "custom-properties" }
      - { method: "GET", path: "/repos/{owner}/{repo}/pulls", area: "pulls", tier: 1, status: "green", mode: "derive", category: "pulls", subcategory: "pulls" }
      - { method: "GET", path: "/repos/{owner}/{repo}/pulls/{pull_number}", area: "pulls", tier: 1, status: "green", mode: "derive", category: "pulls", subcategory: "pulls" }
      - { method: "GET", path: "/repos/{owner}/{repo}/pulls/{pull_number}/comments", area: "pulls", tier: 1, status: "green", mode: "derive", category: "pulls", subcategory: "comments" }
      - { method: "GET", path: "/repos/{owner}/{repo}/pulls/{pull_number}/commits", area: "pulls", tier: 1, status: "green", mode: "derive", category: "pulls", subcategory: "pulls" }
      - { method: "GET", path: "/repos/{owner}/{repo}/pulls/{pull_number}/files", area: "pulls", tier: 1, status: "green", mode: "derive", mode_reason: "the changed-file list and the merge check are computable from the PR's commits and git trees", category: "pulls", subcategory: "pulls" }
      - { method: "GET", path: "/repos/{owner}/{repo}/pulls/{pull_number}/merge", area: "pulls", tier: 1, status: "green", mode: "derive", mode_reason: "the changed-file list and the merge check are computable from the PR's commits and git trees", category: "pulls", subcategory: "pulls" }
      - { method: "GET", path: "/repos/{owner}/{repo}/pulls/{pull_number}/requested_reviewers", area: "pulls", tier: 1, status: "green", mode: "derive", category: "pulls", subcategory: "review-requests" }
      - { method: "GET", path: "/repos/{owner}/{repo}/pulls/{pull_number}/reviews", area: "pulls", tier: 1, status: "green", mode: "derive", category: "pulls", subcategory: "reviews" }
      - { method: "GET", path: "/repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}", area: "pulls", tier: 1, status: "green", mode: "derive", mode_reason: "a single review and its comments over review/review_comment", category: "pulls", subcategory: "reviews" }
      - { method: "GET", path: "/repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}/comments", area: "pulls", tier: 1, status: "green", mode: "empty", mode_reason: "NO REVIEW COMMENT IN THIS UNIVERSE BELONGS TO A REVIEW. `review_comment.review` is NULL on every one of the 100 rows, which is why `shapePullReviewComment` has always rendered `pull_request_review_id: null` — so a review's comment list is empty BY THE DATA, and the response agrees with the comments' own bodies rather than contradicting them. The comments themselves are served and non-empty at `/pulls/{n}/comments`; only the review→comment edge is missing, and attaching a pull request's comments to its single review would invent a relationship canon never recorded. Falsifiable: the day the generator links a comment to a review, this row goes red. RULED by the founder 2026-09-09", mode_reviewed: "2026-09-09", category: "pulls", subcategory: "reviews" }
      - { method: "GET", path: "/repos/{owner}/{repo}/pulls/comments", area: "pulls", tier: 1, status: "green", mode: "derive", category: "pulls", subcategory: "comments" }
      - { method: "GET", path: "/repos/{owner}/{repo}/pulls/comments/{comment_id}", area: "pulls", tier: 1, status: "green", mode: "derive", category: "pulls", subcategory: "comments" }
      - { method: "GET", path: "/repos/{owner}/{repo}/pulls/comments/{comment_id}/reactions", area: "reactions", tier: 2, status: "green", mode: "derive", mode_reason: "ContentReaction is canon as of hello-15 (features.contentReactions); reactionsFor() answers it and shapeReaction renders GitHub's closed eight-value content enum over the SAME rows GitLab serves as award emoji. The parent resources now carry the reaction-rollup GitHub embeds", mode_reviewed: "2026-09-07", category: "reactions", subcategory: "reactions" }
      - { method: "GET", path: "/repos/{owner}/{repo}/readme", area: "repos", tier: 1, status: "green", mode: "derive", category: "repos", subcategory: "contents" }
      - { method: "GET", path: "/repos/{owner}/{repo}/readme/{dir}", area: "repos", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17 `repoOwnership`): the content-file object for tools/README.md, read through the same fileAt/shapeContentFile path /repos/{o}/{r}/contents/{path} uses — one blob, one answer, whichever route asks, which conformance asserts by comparing the two objects. hello-17 puts a README inside a directory for the first time (decisions/2026-09-11-2256): tools/ holds probe/ and report/, both real programs with real source in the tree, so every sentence in the document names something a caller can open — which is the whole reason a folder README is safe to write (invariant #5), and conformance checks it. A DIRECTORY WITH NO README IS GITHUB'S OWN 404 and carries no coverage header: /readme/src is a fact about that directory rather than a gap, and conformance asserts both. An artifact whose tree carries neither ownership file answers the hello-17 generation gap instead, because on it NO directory has a README and the row is unanswerable rather than negative", mode_reviewed: "2026-09-12", category: "repos", subcategory: "contents" }
      - { method: "GET", path: "/repos/{owner}/{repo}/releases", area: "releases", tier: 1, status: "green", mode: "derive", category: "releases", subcategory: "releases" }
      - { method: "GET", path: "/repos/{owner}/{repo}/releases/{release_id}", area: "releases", tier: 1, status: "green", mode: "derive", category: "releases", subcategory: "releases" }
      - { method: "GET", path: "/repos/{owner}/{repo}/releases/{release_id}/assets", area: "releases", tier: 1, status: "green", mode: "derive", mode_reason: "release assets over the release the tag already resolves to (14-hit demand cluster, telemetry 2026-09-01)", category: "releases", subcategory: "assets" }
      - { method: "GET", path: "/repos/{owner}/{repo}/releases/{release_id}/reactions", area: "reactions", tier: 2, status: "green", mode: "derive", mode_reason: "ContentReaction is canon as of hello-15 (features.contentReactions); reactionsFor() answers it and shapeReaction renders GitHub's closed eight-value content enum over the SAME rows GitLab serves as award emoji. The parent resources now carry the reaction-rollup GitHub embeds", mode_reviewed: "2026-09-07", category: "reactions", subcategory: "reactions" }
      - { method: "GET", path: "/repos/{owner}/{repo}/releases/assets/{asset_id}", area: "releases", tier: 1, status: "green", mode: "derive", mode_reason: "release assets over the release the tag already resolves to (14-hit demand cluster, telemetry 2026-09-01)", category: "releases", subcategory: "assets" }
      - { method: "GET", path: "/repos/{owner}/{repo}/releases/latest", area: "releases", tier: 1, status: "green", mode: "derive", category: "releases", subcategory: "releases" }
      - { method: "GET", path: "/repos/{owner}/{repo}/releases/tags/{tag}", area: "releases", tier: 1, status: "green", mode: "derive", category: "releases", subcategory: "releases" }
      - { method: "GET", path: "/repos/{owner}/{repo}/rules/branches/{branch}", area: "rulesets", tier: 3, status: "green", mode: "empty", mode_reason: "no ruleset exists at either scope — canon's only ref-protection rows (`protected_ref`, 2) are scoped to `namespace-001`, a container GitHub has no counterpart for, and repo-01 carries an empty `namespace` column; classic branch protection on `main` (branch.protected=1, served by render-protection.ts) is GitHub's OTHER mechanism and does not imply a ruleset, so GitHub's own answer for a scope with no rulesets is `[]` at 200. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", category: "repos", subcategory: "rules" }
      - { method: "GET", path: "/repos/{owner}/{repo}/rulesets", area: "rulesets", tier: 3, status: "green", mode: "empty", mode_reason: "no ruleset exists at either scope — canon's only ref-protection rows (`protected_ref`, 2) are scoped to `namespace-001`, a container GitHub has no counterpart for, and repo-01 carries an empty `namespace` column; classic branch protection on `main` (branch.protected=1, served by render-protection.ts) is GitHub's OTHER mechanism and does not imply a ruleset, so GitHub's own answer for a scope with no rulesets is `[]` at 200. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", category: "repos", subcategory: "rules" }
      - { method: "GET", path: "/repos/{owner}/{repo}/rulesets/{ruleset_id}", area: "rulesets", tier: 3, status: "planned", mode: "generate", mode_reason: "new canon entity Ruleset", category: "repos", subcategory: "rules" }
      - { method: "GET", path: "/repos/{owner}/{repo}/rulesets/{ruleset_id}/history", area: "rulesets", tier: 3, status: "planned", mode: "generate", mode_reason: "new canon entity Ruleset", category: "repos", subcategory: "rules" }
      - { method: "GET", path: "/repos/{owner}/{repo}/rulesets/{ruleset_id}/history/{version_id}", area: "rulesets", tier: 3, status: "planned", mode: "generate", mode_reason: "new canon entity Ruleset", category: "repos", subcategory: "rules" }
      - { method: "GET", path: "/repos/{owner}/{repo}/rulesets/rule-suites", area: "rulesets", tier: 3, status: "green", mode: "empty", mode_reason: "no ruleset exists at either scope — canon's only ref-protection rows (`protected_ref`, 2) are scoped to `namespace-001`, a container GitHub has no counterpart for, and repo-01 carries an empty `namespace` column; classic branch protection on `main` (branch.protected=1, served by render-protection.ts) is GitHub's OTHER mechanism and does not imply a ruleset, so GitHub's own answer for a scope with no rulesets is `[]` at 200. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", category: "repos", subcategory: "rule-suites" }
      - { method: "GET", path: "/repos/{owner}/{repo}/rulesets/rule-suites/{rule_suite_id}", area: "rulesets", tier: 3, status: "planned", mode: "generate", mode_reason: "new canon entity Ruleset", category: "repos", subcategory: "rule-suites" }
      - { method: "GET", path: "/repos/{owner}/{repo}/secret-scanning/alerts", area: "secret-scanning", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityFinding", category: "secret-scanning", subcategory: "secret-scanning" }
      - { method: "GET", path: "/repos/{owner}/{repo}/secret-scanning/alerts/{alert_number}", area: "secret-scanning", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityFinding", category: "secret-scanning", subcategory: "secret-scanning" }
      - { method: "GET", path: "/repos/{owner}/{repo}/secret-scanning/alerts/{alert_number}/locations", area: "secret-scanning", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityFinding", category: "secret-scanning", subcategory: "secret-scanning" }
      - { method: "GET", path: "/repos/{owner}/{repo}/secret-scanning/custom-patterns", area: "secret-scanning", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityConfiguration", category: "secret-scanning", subcategory: "custom-patterns" }
      - { method: "GET", path: "/repos/{owner}/{repo}/secret-scanning/scan-history", area: "secret-scanning", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityFinding", category: "secret-scanning", subcategory: "secret-scanning" }
      - { method: "GET", path: "/repos/{owner}/{repo}/security-advisories", area: "security-advisories", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityAdvisory", category: "security-advisories", subcategory: "repository-advisories", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/security-advisories/{ghsa_id}", area: "security-advisories", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityAdvisory", category: "security-advisories", subcategory: "repository-advisories", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/stacks", area: "pulls", tier: 1, status: "green", mode: "empty", mode_reason: "no pull request in this universe is stacked on another — all 24 `pull` rows carry `base_branch='main'` and no pull's base is another pull's head (0 rows on that self-join); GitHub's own answer for a repository with no stacks is `[]` at 200. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", category: "pulls", subcategory: "stacks" }
      - { method: "GET", path: "/repos/{owner}/{repo}/stacks/{stack_number}", area: "pulls", tier: 1, status: "planned", mode: "generate", mode_reason: "new canon entity PullStack", category: "pulls", subcategory: "stacks" }
      - { method: "GET", path: "/repos/{owner}/{repo}/stargazers", area: "traffic-stars", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Star", category: "activity", subcategory: "starring" }
      - { method: "GET", path: "/repos/{owner}/{repo}/stats/code_frequency", area: "metrics", tier: 3, status: "green", mode: "derive", mode_reason: "every statistic is an aggregation over commits (authors, weeks, additions/deletions)", category: "metrics", subcategory: "statistics", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/stats/commit_activity", area: "metrics", tier: 3, status: "green", mode: "derive", mode_reason: "every statistic is an aggregation over commits (authors, weeks, additions/deletions)", category: "metrics", subcategory: "statistics", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/stats/contributors", area: "metrics", tier: 3, status: "green", mode: "derive", mode_reason: "every statistic is an aggregation over commits (authors, weeks, additions/deletions)", category: "metrics", subcategory: "statistics", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/stats/participation", area: "metrics", tier: 3, status: "green", mode: "derive", mode_reason: "every statistic is an aggregation over commits (authors, weeks, additions/deletions)", category: "metrics", subcategory: "statistics", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/stats/punch_card", area: "metrics", tier: 3, status: "green", mode: "derive", mode_reason: "every statistic is an aggregation over commits (authors, weeks, additions/deletions)", category: "metrics", subcategory: "statistics", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/subscribers", area: "traffic-stars", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity RepoSubscription", category: "activity", subcategory: "watching" }
      - { method: "GET", path: "/repos/{owner}/{repo}/subscription", area: "traffic-stars", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity RepoSubscription", category: "activity", subcategory: "watching" }
      - { method: "GET", path: "/repos/{owner}/{repo}/tags", area: "repos", tier: 1, status: "green", mode: "derive", category: "repos", subcategory: "repos" }
      - { method: "GET", path: "/repos/{owner}/{repo}/tarball/{ref}", area: "repos", tier: 1, status: "green", mode: "derive", mode_reason: "the file model already carries the tree, so the archive is a ustar+gzip container around the same blobs the contents endpoints and the git transport serve; the documented 302 is simulated in-app (founder ruling 2026-09-02) and the Location names the resolved commit sha", mode_reviewed: "2026-09-02", category: "repos", subcategory: "contents" }
      - { method: "GET", path: "/repos/{owner}/{repo}/teams", area: "repos", tier: 1, status: "green", mode: "derive", category: "repos", subcategory: "repos" }
      - { method: "GET", path: "/repos/{owner}/{repo}/topics", area: "repos", tier: 1, status: "green", mode: "derive", mode_reason: "STALE REASON (\"new canon entity RepoTopic\"): there is no entity to build. `repo.topics_json` holds the list and `shapeRepo` has published it inside the repository object since GitHub coverage began; `topic`'s one required member is `names`, and conformance asserts the standalone list and the embedded one agree", mode_reviewed: "2026-09-12", category: "repos", subcategory: "repos" }
      - { method: "GET", path: "/repos/{owner}/{repo}/traffic/clones", area: "metrics", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity RepoTraffic", category: "metrics", subcategory: "traffic", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/traffic/popular/paths", area: "metrics", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity RepoTraffic", category: "metrics", subcategory: "traffic", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/traffic/popular/referrers", area: "metrics", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity RepoTraffic", category: "metrics", subcategory: "traffic", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/traffic/views", area: "metrics", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity RepoTraffic", category: "metrics", subcategory: "traffic", flag: "needs-tier-review" }
      - { method: "GET", path: "/repos/{owner}/{repo}/vulnerability-alerts", area: "repos", tier: 1, status: "planned", mode: "refuse", mode_reason: "no GitHub security product is enabled on olympus-labs/parthenon — canon carries no security-finding entity and no code-security configuration, and the org's only repository is private; GitHub's own answer for a repository not enabled with vulnerability alerts is 404 with no body (the spec declares only 204 and 404 for this operation). RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", category: "repos", subcategory: "repos" }
      - { method: "GET", path: "/repos/{owner}/{repo}/zipball/{ref}", area: "repos", tier: 1, status: "green", mode: "derive", mode_reason: "the zip half of the tarball row: the same tree, the same blobs, deflated into a zip container; the documented 302 is simulated in-app (founder ruling 2026-09-02)", mode_reviewed: "2026-09-02", category: "repos", subcategory: "contents" }
      - { method: "GET", path: "/repositories", area: "repos", tier: 1, status: "green", mode: "derive", category: "repos", subcategory: "repos" }
      - { method: "GET", path: "/search/code", area: "search", tier: 2, status: "green", mode: "derive", mode_reason: "search over the artifact rows the other search endpoints already query", category: "search", subcategory: "search" }
      - { method: "GET", path: "/search/commits", area: "search", tier: 2, status: "green", mode: "derive", mode_reason: "search over the artifact rows the other search endpoints already query", category: "search", subcategory: "search" }
      - { method: "GET", path: "/search/issues", area: "search", tier: 2, status: "green", mode: "derive", category: "search", subcategory: "search" }
      - { method: "GET", path: "/search/labels", area: "search", tier: 2, status: "green", mode: "derive", mode_reason: "search over the artifact rows the other search endpoints already query", category: "search", subcategory: "search" }
      - { method: "GET", path: "/search/repositories", area: "search", tier: 2, status: "green", mode: "derive", category: "search", subcategory: "search" }
      - { method: "GET", path: "/search/topics", area: "search", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity RepoTopic", category: "search", subcategory: "search" }
      - { method: "GET", path: "/search/users", area: "search", tier: 2, status: "green", mode: "derive", category: "search", subcategory: "search" }
      - { method: "GET", path: "/teams/{team_id}", area: "teams", tier: 1, status: "green", mode: "derive", mode_reason: "teams, their repo grants and the caller's own team list, over team/team_member", category: "teams", subcategory: "teams" }
      - { method: "GET", path: "/teams/{team_id}/invitations", area: "teams", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): the same list through the legacy team id — teamByLegacyId plus reader.listMemberships(\"team\", team) (reader.ts:2961). Conformance asserts the legacy and slug forms are byte-identical", mode_reviewed: "2026-09-09", category: "teams", subcategory: "members" }
      - { method: "GET", path: "/teams/{team_id}/members", area: "teams", tier: 1, status: "green", mode: "derive", mode_reason: "team members over team_member, addressed by legacy team id", category: "teams", subcategory: "members" }
      - { method: "GET", path: "/teams/{team_id}/members/{username}", area: "teams", tier: 1, status: "green", mode: "derive", mode_reason: "team members over team_member, addressed by legacy team id", category: "teams", subcategory: "members" }
      - { method: "GET", path: "/teams/{team_id}/memberships/{username}", area: "teams", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): the same row through the legacy team id — teamByLegacyId (render-access.ts) plus reader.membershipFor(\"team\", team, person) (reader.ts:2977). `url` is the address the caller used, and conformance asserts the legacy and slug forms agree about role and state", mode_reviewed: "2026-09-09", category: "teams", subcategory: "members" }
      - { method: "GET", path: "/teams/{team_id}/repos", area: "teams", tier: 1, status: "green", mode: "derive", mode_reason: "teams, their repo grants and the caller's own team list, over team/team_member", category: "teams", subcategory: "teams" }
      - { method: "GET", path: "/teams/{team_id}/repos/{owner}/{repo}", area: "teams", tier: 1, status: "green", mode: "derive", mode_reason: "teams, their repo grants and the caller's own team list, over team/team_member", category: "teams", subcategory: "teams" }
      - { method: "GET", path: "/teams/{team_id}/teams", area: "teams", tier: 1, status: "green", mode: "empty", mode_reason: "the legacy id-addressed twin of the team child-team list, held to the same fact: the org's teams are flat, so no team has a child", mode_reviewed: "2026-09-01", category: "teams", subcategory: "teams" }
      - { method: "GET", path: "/user", area: "users", tier: 1, status: "green", mode: "derive", category: "users", subcategory: "users" }
      - { method: "GET", path: "/user/{account_id}", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "the person table already answers the user list, the by-account-id read and the hovercard", category: "users", subcategory: "users" }
      - { method: "GET", path: "/user/blocks", area: "users", tier: 1, status: "green", mode: "empty", mode_reason: "the caller-scoped twin of the org block list, held to the same fact: nobody is blocked in this universe", mode_reviewed: "2026-09-01", category: "users", subcategory: "blocking" }
      - { method: "GET", path: "/user/blocks/{username}", area: "users", tier: 1, status: "planned", mode: "refuse", mode_reason: "the id half of the caller block pair: with nobody blocked, GitHub answers 404 to the per-user block check", mode_reviewed: "2026-09-01", category: "users", subcategory: "blocking" }
      - { method: "GET", path: "/user/codespaces", area: "codespaces", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no persona in this universe launches a Codespace: every Codespaces object exists only because a write created one, and this universe accepts no writes", mode_reviewed: "2026-09-01", category: "codespaces", subcategory: "codespaces", flag: "needs-tier-review" }
      - { method: "GET", path: "/user/codespaces/{codespace_name}", area: "codespaces", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no persona in this universe launches a Codespace: every Codespaces object exists only because a write created one, and this universe accepts no writes", mode_reviewed: "2026-09-01", category: "codespaces", subcategory: "codespaces", flag: "needs-tier-review" }
      - { method: "GET", path: "/user/codespaces/{codespace_name}/exports/{export_id}", area: "codespaces", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no persona in this universe launches a Codespace: every Codespaces object exists only because a write created one, and this universe accepts no writes", mode_reviewed: "2026-09-01", category: "codespaces", subcategory: "codespaces", flag: "needs-tier-review" }
      - { method: "GET", path: "/user/codespaces/{codespace_name}/machines", area: "codespaces", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no persona in this universe launches a Codespace: every Codespaces object exists only because a write created one, and this universe accepts no writes", mode_reviewed: "2026-09-01", category: "codespaces", subcategory: "machines", flag: "needs-tier-review" }
      - { method: "GET", path: "/user/codespaces/secrets", area: "codespaces", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no persona in this universe launches a Codespace: every Codespaces object exists only because a write created one, and this universe accepts no writes", mode_reviewed: "2026-09-01", category: "codespaces", subcategory: "secrets", flag: "needs-tier-review" }
      - { method: "GET", path: "/user/codespaces/secrets/{secret_name}", area: "codespaces", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no persona in this universe launches a Codespace: every Codespaces object exists only because a write created one, and this universe accepts no writes", mode_reviewed: "2026-09-01", category: "codespaces", subcategory: "secrets", flag: "needs-tier-review" }
      - { method: "GET", path: "/user/codespaces/secrets/{secret_name}/repositories", area: "codespaces", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no persona in this universe launches a Codespace: every Codespaces object exists only because a write created one, and this universe accepts no writes", mode_reviewed: "2026-09-01", category: "codespaces", subcategory: "secrets", flag: "needs-tier-review" }
      - { method: "GET", path: "/user/codespaces/secrets/public-key", area: "codespaces", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no persona in this universe launches a Codespace: every Codespaces object exists only because a write created one, and this universe accepts no writes", mode_reviewed: "2026-09-01", category: "codespaces", subcategory: "secrets", flag: "needs-tier-review" }
      - { method: "GET", path: "/user/docker/conflicts", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Package", category: "packages", subcategory: "packages" }
      - { method: "GET", path: "/user/emails", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): reader.credentialsForPerson(athena, \"email\") (reader.ts:3016) — athena is the caller GET /user reports. `verified` is `state === active`, a column rather than a decision, so an address canon ever revokes stops being verified in the same edit. `visibility` is `private` on the primary address and null on every other, which is GitHub's own shape and agrees with what /users/{username} publishes: the `users.noreply` form, which is exactly what GitHub shows for a person whose addresses are private", mode_reviewed: "2026-09-09", category: "users", subcategory: "emails" }
      - { method: "GET", path: "/user/followers", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): reader.followers(athena) behind reader.hasSocialGraph(), shaped as `simple-user` through the same shaper /orgs/{org}/members uses, so a login here is a login that fetches. hello-17 `socialGraph` (decisions/2026-09-11-0200) derives the follow graph from the review log and draws nothing: a reviewer follows the author whose changes they read, and an author follows back ONLY a reviewer who APPROVED. Without that second, narrower rule the graph would be the symmetric closure of the review graph wearing two columns, so `followers` and `following` are genuinely different lists rather than one list served twice. The same person_follow table answers GitLab's /users/{id}/followers, which is the cross-host parity that provider's coverage reason already committed to. Conformance asserts this list and /users/athena/followers are the same list, and that every follower reports following the caller from the other end. An artifact that predates the domain answers the hello-17 generation gap: [] there would assert that nobody in THAT universe follows anybody, a statement its canon never made.", mode_reviewed: "2026-09-12", category: "users", subcategory: "followers" }
      - { method: "GET", path: "/user/following", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): reader.following(athena) behind reader.hasSocialGraph(). hello-17 `socialGraph` (decisions/2026-09-11-0200) derives the follow graph from the review log and draws nothing: a reviewer follows the author whose changes they read, and an author follows back ONLY a reviewer who APPROVED. Without that second, narrower rule the graph would be the symmetric closure of the review graph wearing two columns, so `followers` and `following` are genuinely different lists rather than one list served twice. The same person_follow table answers GitLab's /users/{id}/followers, which is the cross-host parity that provider's coverage reason already committed to. Conformance asserts this list and /users/athena/following are the same list. An artifact that predates the domain answers the hello-17 generation gap: [] there would assert that nobody in THAT universe follows anybody, a statement its canon never made.", mode_reviewed: "2026-09-12", category: "users", subcategory: "followers" }
      - { method: "GET", path: "/user/following/{username}", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): GitHub's 204 when the edge exists and its 404 when it does not, with no body either way. The 404 is a fact about the graph rather than a coverage miss, so it carries no coverage header; conformance drives a person the caller does follow, a member she does not, and a login nobody carries, so a green is not \"this route says yes to everything\". An artifact that predates the domain answers the hello-17 generation gap: [] there would assert that nobody in THAT universe follows anybody, a statement its canon never made.", mode_reviewed: "2026-09-12", category: "users", subcategory: "followers" }
      - { method: "GET", path: "/user/gpg_keys", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): reader.credentialsForPerson(athena, \"gpg\") behind reader.hasCallerCredentials(), validated against `gpg-key` and serving a real OpenPGP v4 packet whose long key id a client can recompute from the packet body. hello-17 `callerCredentials` (decisions/2026-09-11-0151) replaces the credential pass's activity thresholds with a rule — THE FOUNDING MEMBER HOLDS ONE OF EVERY CREDENTIAL KIND THIS ORGANIZATION ACCEPTS — and makes the founding member the TEMPLATE'S FIRST PERSONA, which is the login VIEWER_LOGIN resolves to. That is what answers the hello-16 ask on this row (\"the authenticated persona holds none of this kind\"), and it answers it structurally rather than by moving a threshold until it happened to catch her. ONE SHAPE FOR BOTH SURFACES: GitHub publishes `gpg-key` on the caller's list and on /users/{username}/gpg_keys, so this row reuses that shaper rather than writing a second one, and conformance asserts the two lists are byte-identical. A hello-16 artifact answers the hello-17 generation gap and NOT hello-16's: it HAS the person_credential table — somebody else's keys are served off it — and none of these rows, which is why the gate is reader.hasCallerCredentials() and not reader.hasCredentials().", mode_reviewed: "2026-09-12", category: "users", subcategory: "gpg-keys" }
      - { method: "GET", path: "/user/gpg_keys/{gpg_key_id}", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): the caller's own GPG key by its number, the same object the list publishes (conformance compares them field for field). hello-17 `callerCredentials` (decisions/2026-09-11-0151) replaces the credential pass's activity thresholds with a rule — THE FOUNDING MEMBER HOLDS ONE OF EVERY CREDENTIAL KIND THIS ORGANIZATION ACCEPTS — and makes the founding member the TEMPLATE'S FIRST PERSONA, which is the login VIEWER_LOGIN resolves to. That is what answers the hello-16 ask on this row (\"the authenticated persona holds none of this kind\"), and it answers it structurally rather than by moving a threshold until it happened to catch her. A hello-16 artifact answers the hello-17 generation gap and NOT hello-16's: it HAS the person_credential table — somebody else's keys are served off it — and none of these rows, which is why the gate is reader.hasCallerCredentials() and not reader.hasCredentials().", mode_reviewed: "2026-09-12", category: "users", subcategory: "gpg-keys" }
      - { method: "GET", path: "/user/installations", area: "apps", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity GitHubApp", category: "apps", subcategory: "installations", flag: "needs-tier-review" }
      - { method: "GET", path: "/user/installations/{installation_id}/repositories", area: "apps", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity GitHubApp", category: "apps", subcategory: "installations", flag: "needs-tier-review" }
      - { method: "GET", path: "/user/interaction-limits", area: "interactions", tier: 3, status: "green", mode: "empty", mode_reason: "no interaction limit is active anywhere in this universe — olympus-labs is a private organization whose one repository is private (repo.visibility='private'), so there is no drive-by traffic to limit and nobody has set one; GitHub's own answer for a scope with no active limit is `{}` at 200 (the spec's 200 has no required member). RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", category: "interactions", subcategory: "user", flag: "needs-tier-review" }
      - { method: "GET", path: "/user/issues", area: "issues", tier: 1, status: "green", mode: "derive", mode_reason: "issue lists across the repo, org and authenticated persona", category: "issues", subcategory: "issues" }
      - { method: "GET", path: "/user/keys", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): reader.credentialsForPerson(athena, \"ssh-auth\") behind reader.hasCallerCredentials(), validated against `key`. hello-17 `callerCredentials` (decisions/2026-09-11-0151) replaces the credential pass's activity thresholds with a rule — THE FOUNDING MEMBER HOLDS ONE OF EVERY CREDENTIAL KIND THIS ORGANIZATION ACCEPTS — and makes the founding member the TEMPLATE'S FIRST PERSONA, which is the login VIEWER_LOGIN resolves to. That is what answers the hello-16 ask on this row (\"the authenticated persona holds none of this kind\"), and it answers it structurally rather than by moving a threshold until it happened to catch her. A `key` SHAPER HAD TO BE WRITTEN FOR THIS ROW and deliberately did not exist before (decisions/2026-09-09-2008 recorded its absence: it would have been code for a response nothing could produce). Its four judgments are facts rather than defaults: `read_only: false` because canon's `ssh-auth` kind is the key its owner PUSHES with (the opposite reading `shapeDeployKey` makes for the opposite kind), `verified` off the state column exactly as shapeEmail reads it, `last_used` off canon's own epoch, and the material split by the same splitSshLine /users/{username}/keys uses — so the caller's view and the public view of one row cannot describe different bytes, which conformance asserts. `url` is this host's own by-id route, which answers. A hello-16 artifact answers the hello-17 generation gap and NOT hello-16's: it HAS the person_credential table — somebody else's keys are served off it — and none of these rows, which is why the gate is reader.hasCallerCredentials() and not reader.hasCredentials().", mode_reviewed: "2026-09-12", category: "users", subcategory: "keys" }
      - { method: "GET", path: "/user/keys/{key_id}", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): the caller's own key by its number, through the same reader.credentialsForPerson(athena, \"ssh-auth\") read the list uses, so the two are the SAME object field for field (conformance compares them). hello-17 `callerCredentials` (decisions/2026-09-11-0151) replaces the credential pass's activity thresholds with a rule — THE FOUNDING MEMBER HOLDS ONE OF EVERY CREDENTIAL KIND THIS ORGANIZATION ACCEPTS — and makes the founding member the TEMPLATE'S FIRST PERSONA, which is the login VIEWER_LOGIN resolves to. That is what answers the hello-16 ask on this row (\"the authenticated persona holds none of this kind\"), and it answers it structurally rather than by moving a threshold until it happened to catch her. A key id that belongs to somebody ELSE is GitHub's 404 here rather than that person's key, which is the whole difference between this operation and /users/{username}/keys — conformance walks hermes's ids and asserts every one 404s. A hello-16 artifact answers the hello-17 generation gap and NOT hello-16's: it HAS the person_credential table — somebody else's keys are served off it — and none of these rows, which is why the gate is reader.hasCallerCredentials() and not reader.hasCredentials().", mode_reviewed: "2026-09-12", category: "users", subcategory: "keys" }
      - { method: "GET", path: "/user/marketplace_purchases", area: "apps", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the org is neither a GitHub Marketplace listing nor a purchaser, and GitHub answers 404 to marketplace reads for an account with no listing", mode_reviewed: "2026-09-01", category: "apps", subcategory: "marketplace", flag: "needs-tier-review" }
      - { method: "GET", path: "/user/marketplace_purchases/stubbed", area: "apps", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the org is neither a GitHub Marketplace listing nor a purchaser, and GitHub answers 404 to marketplace reads for an account with no listing", mode_reviewed: "2026-09-01", category: "apps", subcategory: "marketplace", flag: "needs-tier-review" }
      - { method: "GET", path: "/user/memberships/orgs", area: "orgs", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): reader.membershipsForPerson(athena) (reader.ts:2969) narrowed to org scope — athena is the caller GET /user already reports, and conformance asserts the two agree. `?state=` is really honored: the pending page is empty rather than the active row, and a value outside the enum is an explicit 400 instead of an unfiltered 200 (DECISIONS 2026-08-21)", mode_reviewed: "2026-09-09", category: "orgs", subcategory: "members" }
      - { method: "GET", path: "/user/memberships/orgs/{org}", area: "orgs", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): the same membership addressed by organization — reader.membershipFor(\"org\", org, athena) (reader.ts:2977), byte-identical to the row the listing serves. An organization this host does not serve is GitHub's own 404", mode_reviewed: "2026-09-09", category: "orgs", subcategory: "members" }
      - { method: "GET", path: "/user/migrations", area: "migrations", tier: 3, status: "deferred", mode: "refuse", mode_reason: "a migration or a source import exists only because someone started one; this universe has never run either, so GitHub answers 404 for the job that was never created", mode_reviewed: "2026-09-01", category: "migrations", subcategory: "users" }
      - { method: "GET", path: "/user/migrations/{migration_id}", area: "migrations", tier: 3, status: "deferred", mode: "refuse", mode_reason: "a migration or a source import exists only because someone started one; this universe has never run either, so GitHub answers 404 for the job that was never created", mode_reviewed: "2026-09-01", category: "migrations", subcategory: "users" }
      - { method: "GET", path: "/user/migrations/{migration_id}/archive", area: "migrations", tier: 3, status: "deferred", mode: "refuse", mode_reason: "a migration or a source import exists only because someone started one; this universe has never run either, so GitHub answers 404 for the job that was never created", mode_reviewed: "2026-09-01", category: "migrations", subcategory: "users" }
      - { method: "GET", path: "/user/migrations/{migration_id}/repositories", area: "migrations", tier: 3, status: "deferred", mode: "refuse", mode_reason: "a migration or a source import exists only because someone started one; this universe has never run either, so GitHub answers 404 for the job that was never created", mode_reviewed: "2026-09-01", category: "migrations", subcategory: "users" }
      - { method: "GET", path: "/user/orgs", area: "orgs", tier: 1, status: "green", mode: "derive", category: "orgs", subcategory: "orgs" }
      - { method: "GET", path: "/user/packages", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Package", category: "packages", subcategory: "packages" }
      - { method: "GET", path: "/user/packages/{package_type}/{package_name}", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Package", category: "packages", subcategory: "packages" }
      - { method: "GET", path: "/user/packages/{package_type}/{package_name}/versions", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Package", category: "packages", subcategory: "packages" }
      - { method: "GET", path: "/user/packages/{package_type}/{package_name}/versions/{package_version_id}", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Package", category: "packages", subcategory: "packages" }
      - { method: "GET", path: "/user/public_emails", area: "users", tier: 1, status: "green", mode: "empty", mode_reason: "NO ADDRESS IN THIS UNIVERSE IS PUBLIC, and that is a property of the credential canon rather than of who the caller is. packages/renderer-github/src/render-credentials.ts decides `visibility` from a COLUMN — \"private\" on the primary address and null on every other, which is GitHub's own shape — and /users/{username} publishes {login}@users.noreply.sandboxapis.dev from the other side, which is exactly what GitHub shows for a person whose addresses are private. The publicly-visible subset of anybody's addresses here is therefore genuinely empty, and GitHub's own answer for a caller who publishes none is [] at 200. SERVED 2026-09-12 (hello-17 GitHub wave) behind reader.hasCredentials() — the domain that decides the answer, not hello-17's caller half, because the claim holds on a hello-16 artifact exactly as it does on a hello-17 one. Falsifiable: the conformance entry's expectsEmpty fails the day canon gives an address a public visibility, and it also asserts the caller DOES hold addresses, so an empty page cannot go green on a universe with no email canon. This supersedes the 2026-09-09 ruling that the emptiness was \"about the caller\": hello-17 makes the caller the template's first persona structurally (decisions/2026-09-11-0151), and the visibility column was always the thing deciding this row. RULED empty by the hello-17 GitHub wave, 2026-09-12 — flagged for founder confirmation in the PR", mode_reviewed: "2026-09-12", category: "users", subcategory: "emails" }
      - { method: "GET", path: "/user/repos", area: "repos", tier: 1, status: "green", mode: "derive", category: "repos", subcategory: "repos" }
      - { method: "GET", path: "/user/repository_invitations", area: "repos", tier: 1, status: "green", mode: "empty", mode_reason: "no pending repository invitations in this universe: reader.membershipsForPerson(athena) (reader.ts:2969) carries no pending repository row, because nobody here has been offered a repository. It is the caller's side of /repos/{owner}/{repo}/invitations and answers the same fact, so conformance asserts the two agree. SERVED 2026-09-10 as GitHub's empty array, behind the hello-16 generation gate — RULED EMPTY by the founder 2026-09-10", mode_reviewed: "2026-09-10", category: "collaborators", subcategory: "invitations" }
      - { method: "GET", path: "/user/social_accounts", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): reader.credentialsForPerson(athena, \"social\") (reader.ts:3016). Two providers, and the omissions are the design (packages/canon/src/credentials.ts): a row claiming a large proprietary network would carry a URL at somebody else's live service, naming an account that either does not exist or belongs to a real person. Both values resolve inside this organization's own domain, and conformance asserts the caller's list and /users/athena/social_accounts are byte-identical", mode_reviewed: "2026-09-09", category: "users", subcategory: "social-accounts" }
      - { method: "GET", path: "/user/ssh_signing_keys", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): reader.credentialsForPerson(athena, \"ssh-signing\") behind reader.hasCallerCredentials(), validated against `ssh-signing-key`. hello-17 `callerCredentials` (decisions/2026-09-11-0151) replaces the credential pass's activity thresholds with a rule — THE FOUNDING MEMBER HOLDS ONE OF EVERY CREDENTIAL KIND THIS ORGANIZATION ACCEPTS — and makes the founding member the TEMPLATE'S FIRST PERSONA, which is the login VIEWER_LOGIN resolves to. That is what answers the hello-16 ask on this row (\"the authenticated persona holds none of this kind\"), and it answers it structurally rather than by moving a threshold until it happened to catch her. A SIGNING KEY IS A SEPARATE GRANT FROM AN AUTHENTICATION KEY and canon models it as a separate CredentialKind for that reason, so this list and /user/keys must not share material — conformance asserts no key appears on both, because a replica that served one list from both would be asserting a grant nobody made. A hello-16 artifact answers the hello-17 generation gap and NOT hello-16's: it HAS the person_credential table — somebody else's keys are served off it — and none of these rows, which is why the gate is reader.hasCallerCredentials() and not reader.hasCredentials().", mode_reviewed: "2026-09-12", category: "users", subcategory: "ssh-signing-keys" }
      - { method: "GET", path: "/user/ssh_signing_keys/{ssh_signing_key_id}", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): the caller's own signing key by its number, the same object the list publishes. hello-17 `callerCredentials` (decisions/2026-09-11-0151) replaces the credential pass's activity thresholds with a rule — THE FOUNDING MEMBER HOLDS ONE OF EVERY CREDENTIAL KIND THIS ORGANIZATION ACCEPTS — and makes the founding member the TEMPLATE'S FIRST PERSONA, which is the login VIEWER_LOGIN resolves to. That is what answers the hello-16 ask on this row (\"the authenticated persona holds none of this kind\"), and it answers it structurally rather than by moving a threshold until it happened to catch her. A hello-16 artifact answers the hello-17 generation gap and NOT hello-16's: it HAS the person_credential table — somebody else's keys are served off it — and none of these rows, which is why the gate is reader.hasCallerCredentials() and not reader.hasCredentials().", mode_reviewed: "2026-09-12", category: "users", subcategory: "ssh-signing-keys" }
      - { method: "GET", path: "/user/starred", area: "traffic-stars", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Star", category: "activity", subcategory: "starring" }
      - { method: "GET", path: "/user/starred/{owner}/{repo}", area: "traffic-stars", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Star", category: "activity", subcategory: "starring" }
      - { method: "GET", path: "/user/subscriptions", area: "traffic-stars", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity RepoSubscription", category: "activity", subcategory: "watching" }
      - { method: "GET", path: "/user/teams", area: "teams", tier: 1, status: "green", mode: "derive", mode_reason: "teams, their repo grants and the caller's own team list, over team/team_member", category: "teams", subcategory: "teams" }
      - { method: "GET", path: "/users", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "the person table already answers the user list, the by-account-id read and the hovercard", category: "users", subcategory: "users" }
      - { method: "GET", path: "/users/{username}", area: "users", tier: 1, status: "green", mode: "derive", category: "users", subcategory: "users" }
      - { method: "GET", path: "/users/{username}/attestations/{subject_digest}", area: "users", tier: 1, status: "green", mode: "empty", mode_reason: "no artifact in this universe is attested — all 392 `artifact` rows are plain workflow-run uploads with no provenance bundle and none of the three workflows (`ci`, `lint`, `release`) runs an attestation step; GitHub's own answer for a subject digest with no attestations is `{attestations: []}` at 200 (the spec's 200 has NO required member). The operation also declares a 404 and the ORCHESTRATOR RULED the 200: a digest is a content address rather than a resource id, so asking about an artifact nobody signed is a well-formed question whose answer is \"none\". RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", category: "users", subcategory: "attestations" }
      - { method: "GET", path: "/users/{username}/copilot-spaces", area: "copilot-spaces", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity CopilotSpace", category: "copilot-spaces", subcategory: "copilot-spaces", flag: "needs-tier-review" }
      - { method: "GET", path: "/users/{username}/copilot-spaces/{space_number}", area: "copilot-spaces", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity CopilotSpace", category: "copilot-spaces", subcategory: "copilot-spaces", flag: "needs-tier-review" }
      - { method: "GET", path: "/users/{username}/copilot-spaces/{space_number}/collaborators", area: "copilot-spaces", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity CopilotSpace", category: "copilot-spaces", subcategory: "collaborators", flag: "needs-tier-review" }
      - { method: "GET", path: "/users/{username}/copilot-spaces/{space_number}/resources", area: "copilot-spaces", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity CopilotSpace", category: "copilot-spaces", subcategory: "resources", flag: "needs-tier-review" }
      - { method: "GET", path: "/users/{username}/copilot-spaces/{space_number}/resources/{space_resource_id}", area: "copilot-spaces", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity CopilotSpace", category: "copilot-spaces", subcategory: "resources", flag: "needs-tier-review" }
      - { method: "GET", path: "/users/{username}/docker/conflicts", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Package", category: "packages", subcategory: "packages" }
      - { method: "GET", path: "/users/{username}/events", area: "events-timeline", tier: 2, status: "green", mode: "derive", category: "activity", subcategory: "events" }
      - { method: "GET", path: "/users/{username}/events/orgs/{org}", area: "events-timeline", tier: 2, status: "green", mode: "derive", category: "activity", subcategory: "events" }
      - { method: "GET", path: "/users/{username}/events/public", area: "events-timeline", tier: 2, status: "green", mode: "derive", category: "activity", subcategory: "events" }
      - { method: "GET", path: "/users/{username}/followers", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): anybody's followers, off the same reader.followers() read the caller's list uses. hello-17 `socialGraph` (decisions/2026-09-11-0200) derives the follow graph from the review log and draws nothing: a reviewer follows the author whose changes they read, and an author follows back ONLY a reviewer who APPROVED. Without that second, narrower rule the graph would be the symmetric closure of the review graph wearing two columns, so `followers` and `following` are genuinely different lists rather than one list served twice. The same person_follow table answers GitLab's /users/{id}/followers, which is the cross-host parity that provider's coverage reason already committed to. THE ORG LOGIN IS A VALID {username} AND FOLLOWS NOBODY — the rule /users/{org}/repos already follows, because a 404 here would say the account does not exist while /users/{org} says it does — and conformance asserts the organization account answers [] at 200. An artifact that predates the domain answers the hello-17 generation gap: [] there would assert that nobody in THAT universe follows anybody, a statement its canon never made.", mode_reviewed: "2026-09-12", category: "users", subcategory: "followers" }
      - { method: "GET", path: "/users/{username}/following", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): anybody's following list, off reader.following(). hello-17 `socialGraph` (decisions/2026-09-11-0200) derives the follow graph from the review log and draws nothing: a reviewer follows the author whose changes they read, and an author follows back ONLY a reviewer who APPROVED. Without that second, narrower rule the graph would be the symmetric closure of the review graph wearing two columns, so `followers` and `following` are genuinely different lists rather than one list served twice. The same person_follow table answers GitLab's /users/{id}/followers, which is the cross-host parity that provider's coverage reason already committed to. Conformance walks the whole roster and checks every edge from both ends, which is what proves followers and following are two reads of one asymmetric table rather than one list served twice. An artifact that predates the domain answers the hello-17 generation gap: [] there would assert that nobody in THAT universe follows anybody, a statement its canon never made.", mode_reviewed: "2026-09-12", category: "users", subcategory: "followers" }
      - { method: "GET", path: "/users/{username}/following/{target_user}", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): GitHub's 204/404 pair for any ordered pair of people. Nobody follows themselves — person_follow has no self-edge by construction — and conformance asserts the self-check is a 404, which is where that construction shows on the wire. An artifact that predates the domain answers the hello-17 generation gap: [] there would assert that nobody in THAT universe follows anybody, a statement its canon never made.", mode_reviewed: "2026-09-12", category: "users", subcategory: "followers" }
      - { method: "GET", path: "/users/{username}/gists", area: "gists", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Gist", category: "gists", subcategory: "gists" }
      - { method: "GET", path: "/users/{username}/gpg_keys", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): reader.credentialsForPerson(person, \"gpg\") (reader.ts:3016). `public_key` is a REAL OpenPGP v4 Ed25519 public-key packet body and `key_id` its long id, derived the way GnuPG derives them; the conformance entry parses the packet and checks the version byte, the algorithm and the id's shape rather than trusting the encoder. `raw_key` is null and `emails` is EMPTY for one reason: a transferable key needs a user id and a self-signature, both of which need a private half this universe never generated — so neither is served rather than being faked. `can_sign`/`can_certify` true and both encryption flags false are facts about Ed25519, checkable from the material", mode_reviewed: "2026-09-09", category: "users", subcategory: "gpg-keys" }
      - { method: "GET", path: "/users/{username}/hovercard", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "the person table already answers the user list, the by-account-id read and the hovercard", category: "users", subcategory: "users" }
      - { method: "GET", path: "/users/{username}/installation", area: "apps", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity GitHubApp", category: "apps", subcategory: "apps", flag: "needs-tier-review" }
      - { method: "GET", path: "/users/{username}/keys", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): reader.credentialsForPerson(person, \"ssh-auth\") (reader.ts:3016) in GitHub's `key-simple` shape — the id and the material, with no comment, which is what the public listing carries. Conformance decodes the blob to a 51-byte ssh-ed25519 wire key and re-hashes it to the artifact's own fingerprint_sha256, so `ssh-keygen -lf` on the served line reproduces the served fingerprint. The organization login is a valid {username} here and answers with nothing, the rule /users/{org}/repos already follows", mode_reviewed: "2026-09-09", category: "users", subcategory: "keys" }
      - { method: "GET", path: "/users/{username}/orgs", area: "orgs", tier: 1, status: "green", mode: "derive", category: "orgs", subcategory: "orgs" }
      - { method: "GET", path: "/users/{username}/packages", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Package", category: "packages", subcategory: "packages" }
      - { method: "GET", path: "/users/{username}/packages/{package_type}/{package_name}", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Package", category: "packages", subcategory: "packages" }
      - { method: "GET", path: "/users/{username}/packages/{package_type}/{package_name}/versions", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Package", category: "packages", subcategory: "packages" }
      - { method: "GET", path: "/users/{username}/packages/{package_type}/{package_name}/versions/{package_version_id}", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Package", category: "packages", subcategory: "packages" }
      - { method: "GET", path: "/users/{username}/projectsV2", area: "projects-v2", tier: 2, status: "green", mode: "empty", mode_reason: "no person in this organization owns a project — all 22 `epic` rows carry a `team` and belong to one of the four teams, never to an individual; GitHub's own answer for a user who owns no projects is `[]` at 200. The ORGANIZATION's list is served with real content in the same wave, which is what makes this an answer rather than a gap. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", category: "projects", subcategory: "projects" }
      - { method: "GET", path: "/users/{username}/projectsV2/{project_number}", area: "projects-v2", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Board", category: "projects", subcategory: "projects" }
      - { method: "GET", path: "/users/{username}/projectsV2/{project_number}/fields", area: "projects-v2", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Board", category: "projects", subcategory: "fields" }
      - { method: "GET", path: "/users/{username}/projectsV2/{project_number}/fields/{field_id}", area: "projects-v2", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Board", category: "projects", subcategory: "fields" }
      - { method: "GET", path: "/users/{username}/projectsV2/{project_number}/items", area: "projects-v2", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Board", category: "projects", subcategory: "items" }
      - { method: "GET", path: "/users/{username}/projectsV2/{project_number}/items/{item_id}", area: "projects-v2", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Board", category: "projects", subcategory: "items" }
      - { method: "GET", path: "/users/{username}/projectsV2/{project_number}/views/{view_number}/items", area: "projects-v2", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Board", category: "projects", subcategory: "items" }
      - { method: "GET", path: "/users/{username}/received_events", area: "events-timeline", tier: 2, status: "green", mode: "derive", category: "activity", subcategory: "events" }
      - { method: "GET", path: "/users/{username}/received_events/public", area: "events-timeline", tier: 2, status: "green", mode: "derive", category: "activity", subcategory: "events" }
      - { method: "GET", path: "/users/{username}/repos", area: "repos", tier: 1, status: "green", mode: "derive", category: "repos", subcategory: "repos" }
      - { method: "GET", path: "/users/{username}/settings/billing/ai_credit/usage", area: "billing-admin-enterprise", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity BillingPeriod", category: "billing", subcategory: "usage", flag: "needs-tier-review" }
      - { method: "GET", path: "/users/{username}/settings/billing/premium_request/usage", area: "billing-admin-enterprise", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity BillingPeriod", category: "billing", subcategory: "usage", flag: "needs-tier-review" }
      - { method: "GET", path: "/users/{username}/settings/billing/usage", area: "billing-admin-enterprise", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity BillingPeriod", category: "billing", subcategory: "usage", flag: "needs-tier-review" }
      - { method: "GET", path: "/users/{username}/settings/billing/usage/summary", area: "billing-admin-enterprise", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity BillingPeriod", category: "billing", subcategory: "usage", flag: "needs-tier-review" }
      - { method: "GET", path: "/users/{username}/social_accounts", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): reader.credentialsForPerson(person, \"social\") (reader.ts:3016) — the same rows /user/social_accounts serves for the caller, which conformance asserts are byte-identical for the same person", mode_reviewed: "2026-09-09", category: "users", subcategory: "social-accounts" }
      - { method: "GET", path: "/users/{username}/ssh_signing_keys", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): reader.credentialsForPerson(person, \"ssh-signing\") (reader.ts:3016). A SEPARATE endpoint from /users/{username}/keys because it is a separate grant — a key authorised to write and a key trusted to attest authorship are different things — and conformance asserts no key appears on both lists, because serving one list from two addresses would assert a grant nobody made", mode_reviewed: "2026-09-09", category: "users", subcategory: "ssh-signing-keys" }
      - { method: "GET", path: "/users/{username}/starred", area: "traffic-stars", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Star", category: "activity", subcategory: "starring" }
      - { method: "GET", path: "/users/{username}/subscriptions", area: "traffic-stars", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity RepoSubscription", category: "activity", subcategory: "watching" }
      - { method: "GET", path: "/versions", area: "meta", tier: 1, status: "green", mode: "derive", mode_reason: "reader.refCatalog(\"github.api-versions\") in the artifact's own ord order (newest first), and the version this host stamps into x-github-api-version is asserted to be one of them. licence: FACTUAL — the response is a list of API version DATES (gh api /versions returns [\"2026-03-10\",\"2022-11-28\"]), which carries no authorship, and this host already declares the version each pin emulates. Older pins answer the refCatalogs generation-gap 404 rather than an empty catalogue, which on these rows would be a false claim about the HOST. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", category: "meta", subcategory: "meta" }
      - { method: "GET", path: "/zen", area: "meta", tier: 1, status: "planned", mode: "generate", mode_reason: "static provider catalog, and NOT `derive`: `derive` is defined in this file as computed from artifact rows that already exist, and a vendor catalog is not an artifact row. LICENCE: NO GRANT — the response is one of GitHub's design aphorisms, creative prose GitHub publishes under no licence. The per-item licence finding is coverage/reviews/2026-09-09-hello-15-stale-reasons-git-hosts.md §5.3, and §5.4 records why the label waited for a shard arm", mode_reviewed: "2026-09-09", held: "data-licensing", held_reviewed: "2026-09-09", category: "meta", subcategory: "meta" }
    graphql:
      - { entity: "checks", type: "CheckSuite", tier: 1, status: "green", mode: "derive", graphql_only: false }
      - { entity: "commit-statuses", type: "StatusContext", tier: 1, status: "green", mode: "derive", graphql_only: false }
      - { entity: "discussions", type: "Discussion", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Discussion", graphql_only: true }
      - { entity: "issues", type: "Issue", tier: 1, status: "green", mode: "derive", graphql_only: false }
      - { entity: "orgs", type: "Organization", root_field: "organization", tier: 1, status: "green", mode: "derive", graphql_only: false }
      - { entity: "projects-v2-views", type: "ProjectV2View", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Board", graphql_only: true }
      - { entity: "pulls", type: "PullRequest", tier: 1, status: "green", mode: "derive", graphql_only: false }
      - { entity: "refs", type: "Ref", tier: 1, status: "green", mode: "derive", graphql_only: false }
      - { entity: "releases", type: "Release", tier: 1, status: "green", mode: "derive", graphql_only: false }
      - { entity: "repos", type: "Repository", root_field: "repository", tier: 1, status: "green", mode: "derive", graphql_only: false }
      - { entity: "reviews", type: "PullRequestReview", tier: 1, status: "green", mode: "derive", graphql_only: false }
      - { entity: "teams", type: "Team", tier: 1, status: "green", mode: "derive", graphql_only: false }
      - { entity: "users", type: "User", root_field: "user", tier: 1, status: "green", mode: "derive", graphql_only: false }
    git:
      - { method: "GET", path: "/{owner}/{repo}.git/info/refs", service: "git-upload-pack", tier: 1, status: "green", mode: "derive", policy: "served", note: "ref advertisement, pkt-line; ?service=git-upload-pack only — dumb HTTP is not served and 404s" }
      - { method: "POST", path: "/{owner}/{repo}.git/git-upload-pack", service: "git-upload-pack", tier: 1, status: "green", mode: "derive", policy: "served", note: "fetch negotiation; non-delta packfile v2, side-band-64k, shallow/deepen/unshallow. No partial clone (filter), no protocol v2" }
      - { method: "POST", path: "/{owner}/{repo}.git/git-receive-pack", service: "git-receive-pack", tier: 1, status: "excluded", mode: "read-only", mode_reason: "NOT A READ, and in the manifest for the one reason this mode exists - clients demonstrably probe it, because `git push` is what a developer types next after a clone that worked. The read-only 403 IS its final response (invariant #3) rather than a gap waiting on anything: renderer-github/src/git/routes.ts:120 answers the advertisement `?service=git-receive-pack` with readOnly(c, \"push to this repository (git-receive-pack)\") and the POST is deliberately given NO route at all (routes.ts:134), so both halves of a push refuse identically. The row is `excluded` and never joins the badge denominator, which is what this mode has meant since A0.1 - the zendesk /api/v2/users/me/session/renew precedent (founder ruling 2026-09-06), applied to the fleet's only other excluded row that is a WRITE rather than a scope decision. CLASSIFIED 2026-09-13 (the unjudged-47 pass) and NOT re-ruled: the row's own curated note in git-transport.ts has said exactly this since the transport shipped (DECISIONS 2026-08-23); the mode word was simply never written down beside it. NO NUMBER MOVES - an excluded row is counted in the generation report's (excluded) column either way, and the report's `read-only` column reads 0 whenever the mode is used correctly", mode_reviewed: "2026-09-13", policy: "refused", note: "push — REFUSED by the same read-only boundary as every other write (invariant #3), 403 + provider-shaped body; its advertisement (info/refs?service=git-receive-pack) is refused identically" }
  slack:
    rest:
      - { method: "GET", path: "/api/admin.conversations.search", area: "admin", tier: 3, status: "excluded", mode: "unclassified", tag: "admin" }
      - { method: "POST", path: "/api/auth.test", area: "auth", tier: 1, status: "green", mode: "derive", tag: "auth" }
      - { method: "GET", path: "/api/bookmarks.list", area: "bookmarks", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Bookmark", mode_reviewed: "2026-09-01", tag: "bookmarks" }
      - { method: "GET", path: "/api/conversations.history", area: "conversations", tier: 1, status: "green", mode: "derive", tag: "conversations" }
      - { method: "GET", path: "/api/conversations.info", area: "conversations", tier: 1, status: "green", mode: "derive", tag: "conversations" }
      - { method: "GET", path: "/api/conversations.list", area: "conversations", tier: 1, status: "green", mode: "derive", tag: "conversations" }
      - { method: "GET", path: "/api/conversations.members", area: "conversations", tier: 1, status: "green", mode: "derive", tag: "conversations" }
      - { method: "GET", path: "/api/conversations.replies", area: "conversations", tier: 1, status: "green", mode: "derive", tag: "conversations" }
      - { method: "GET", path: "/api/emoji.list", area: "emoji", tier: 1, status: "green", mode: "empty", mode_reason: "this workspace has no CUSTOM emoji — the canon's reaction emoji are the standard set, which real Slack never lists here (DECISIONS 2026-08-25 [P34/slack] item 6)", mode_reviewed: "2026-08-25", tag: "emoji" }
      - { method: "GET", path: "/api/files.list", area: "files", tier: 2, status: "green", mode: "empty", mode_reason: "no message in this universe carries a file — `message` has no attachment column and the fleet's only file entity, `attachment`, hangs off the support desk's ticket comments and macros and - from hello-18's attachmentParents - issues, issue comments, merge requests, alerts and the namespace, never off a chat message (clause re-worded at the hello-18 cutover 2026-09-12: the canon grew, the conclusion did not move); Slack's own answer for a workspace with no files is {ok:true, files:[], paging:{...}} at 200. RULED by the founder 2026-09-12 (round 19), coverage wave W5. It is already the third statement of one fact on this host: reactions.get refuses a `file` argument with file_not_found, and files.upload is a write", mode_reviewed: "2026-09-12", tag: "files" }
      - { method: "GET", path: "/api/oauth.v2.access", area: "app-auth", tier: 3, status: "excluded", mode: "unclassified", tag: "oauth" }
      - { method: "GET", path: "/api/pins.list", area: "pins", tier: 1, status: "green", mode: "empty", mode_reason: "no message in this workspace is pinned, on any channel — which is what keeps conversations.history's pin_count: 0 coherent (DECISIONS 2026-08-25 [P34/slack] item 6)", mode_reviewed: "2026-08-25", tag: "pins" }
      - { method: "GET", path: "/api/reactions.get", area: "reactions", tier: 1, status: "green", mode: "derive", tag: "reactions" }
      - { method: "GET", path: "/api/rtm.connect", area: "rtm", tier: 3, status: "excluded", mode: "unclassified", tag: "rtm" }
      - { method: "GET", path: "/api/search.messages", area: "search", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED (wave W5) by a BOUNDED message search over the messaging canon — the soql.ts/sosl.ts contract in a third grammar: every modifier outside the subset is refused BY NAME with the coverage headers inside Slack's ok:false envelope, never ignored, because a search that quietly drops `has:link` returns MORE matches than the caller asked for and looks exactly like a correct answer. COVERED: bare terms (all must match, on whole-word tokens), quoted phrases, `in:` by name or id, `from:` by login, id or <@U…>, count/page with the doc's own 100 ceilings, sort=timestamp and sort_dir. REFUSED BY NAME: every other modifier, `-negation`, explicit AND/OR, wildcards, `highlight=true` and cursormark pagination. `sort=score` is NOT refused even though this replica computes no relevance — it is the default, refusing it would refuse every naive call, and the SET and the counts are exact while Slack's match objects carry no score field for us to invent a value for; the order served is the documented newest-first. One narrowing is stated rather than hidden: this replica matches message TEXT only, where the doc says users and channels also match at a lower priority — narrower than the real API, never wider. Matches come from BOTH halves of a channel's history, top-level and thread replies, because this canon puts the detail in the threads", mode_reviewed: "2026-09-12", tag: "search" }
      - { method: "GET", path: "/api/stars.list", area: "stars", tier: 3, status: "excluded", mode: "unclassified", tag: "stars" }
      - { method: "GET", path: "/api/team.info", area: "team", tier: 1, status: "green", mode: "derive", tag: "team" }
      - { method: "GET", path: "/api/usergroups.list", area: "usergroups", tier: 1, status: "green", mode: "derive", tag: "usergroups" }
      - { method: "GET", path: "/api/users.getPresence", area: "presence", tier: 3, status: "excluded", mode: "unclassified", tag: "presence" }
      - { method: "GET", path: "/api/users.info", area: "users", tier: 1, status: "green", mode: "derive", tag: "users" }
      - { method: "GET", path: "/api/users.list", area: "users", tier: 1, status: "green", mode: "derive", tag: "users" }
      - { method: "GET", path: "/api/users.lookupByEmail", area: "users", tier: 1, status: "green", mode: "derive", tag: "users" }
    graphql: [] # no GraphQL API exists for this provider (REST-only)
  sentry:
    rest:
      - { method: "GET", path: "/api/0/organizations/", area: "organizations", tier: 1, status: "green", mode: "derive", tag: "Organizations" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/", area: "organizations", tier: 1, status: "green", mode: "derive", tag: "Organizations" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/alert-rules/", area: "alerts", tier: 2, status: "deferred", mode: "generate", mode_reason: "A WIDENING, NOT A BUILD: canon's `monitor` table is very nearly a Sentry metric alert rule already (packages/artifact/src/rows.ts:548) - id, name, created_epoch (dateCreated), for_sec (timeWindow), comparison (thresholdType), threshold (triggers[].alertThreshold) and service -> projects all map, reader.listMonitors() serves the rows today, and an activation maps field-for-field onto AlertRow (fired_epoch, resolved_epoch, peak_value, state). WHAT IS MISSING IS AN AUTHOR: MonitorRow has no `created_by`, `createdBy` is REQUIRED on Sentry's AlertRule schema, and no other canonical fact answers who wrote a threshold - so a rule cannot be shaped without inventing one. The widening is ONE nullable person column on `monitor`, written at generation time from the owning service's team lead, and the same wave owes a ruling on the three other required fields whose values are Sentry's own vocabulary rather than this universe's data (`query`, `aggregate`, `monitorType`). It unblocks THREE rows, all on this provider - this list, the by-id read and the activations list - and none elsewhere: nothing else in the fleet reads a monitor's author. CLASSIFIED 2026-09-13 (the unjudged-47 pass) on the 2026-09-12 sweep's proposal, which analysed it and left it unclassified", mode_reviewed: "2026-09-13", tag: "Alerts" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/alert-rules/{alert_rule_id}/", area: "alerts", tier: 2, status: "deferred", mode: "generate", mode_reason: "the same rule by id, blocked by the same required `createdBy` the list is - one nullable author column on canon's `monitor`. An id naming no monitor stays Sentry's ordinary 404 either way. CLASSIFIED 2026-09-13 (the unjudged-47 pass)", mode_reviewed: "2026-09-13", tag: "Alerts" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/alert-rules/{alert_rule_id}/activations/", area: "alerts", tier: 2, status: "deferred", mode: "generate", mode_reason: "the activations of one rule. THE ACTIVATION ROWS THEMSELVES ARE ALREADY CANON - AlertRow carries fired_epoch, resolved_epoch, state and peak_value, which is what dateCreated / finishedAt / isComplete / metricValue want - so this row is blocked only because it hangs off a rule that cannot be shaped: the parent must resolve before its children can, and the parent needs the author column. The SAME one-column widening on `monitor` unblocks it. CLASSIFIED 2026-09-13 (the unjudged-47 pass)", mode_reviewed: "2026-09-13", tag: "Alerts" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/dashboards/", area: "dashboards", tier: 2, status: "green", mode: "empty", mode_reason: "nobody in this organization has built a dashboard - verbatim the fact `/discover/saved/` beside it was already ruled on, one entity further on: there is no Dashboard row and no widget row anywhere in the artifact, and listStatusDashboards() is a Statuspage entity in a different domain; Sentry's own answer for an organization with none is `[]` at 200. RULED by the founder 2026-09-12 on the unclassified sweep's proposal, as proposed.", mode_reviewed: "2026-09-12", tag: "Dashboards" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/dashboards/{dashboard_id}/", area: "dashboards", tier: 2, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the empty beside it: the dashboard list serves `[]` on this same host, so no dashboard id resolves and Sentry's own 404 is the whole answer. RULED by the founder 2026-09-12 on the unclassified sweep's proposal, as proposed.", mode_reviewed: "2026-09-12", tag: "Dashboards" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/discover/saved/", area: "discover", tier: 2, status: "green", mode: "empty", mode_reason: "nobody in this organization has saved a Discover query - canon's saved queries are the Zendesk ticket views in saved_search (record_kind=ticket, owned by crm-user rows) and, from hello-18's savedFilters, the Jira-shaped rows in saved_filter - and neither table carries a Sentry-scoped Discover query (clause re-worded at the hello-18 cutover 2026-09-12: the canon grew, the conclusion did not move); Sentry's own answer for an organization with none is `[]` at 200; RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Discover" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/discover/saved/{query_id}/", area: "discover", tier: 2, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the empty beside it: the saved-query list serves `[]`, so no query id resolves and Sentry's own 404 is the whole answer; RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Discover" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/environments/", area: "environments", tier: 1, status: "green", mode: "derive", tag: "Environments" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/eventids/{event_id}/", area: "organizations", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12: the ORG-scoped twin of /projects/{org}/{proj}/events/{event_id}/, which has been `derive` since 2026-09-01. Every required field (event/eventId/groupId/organizationSlug/projectSlug) is the same lookup without the project scope, and the embedded event is byte-identical to the project-scoped read of the same id", mode_reviewed: "2026-09-12", tag: "Organizations" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/events/", area: "discover", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12: Discover over the real event store (error_event, every row a real error at a real instant). The covered field set is closed and named - id, issue, issue.id, project, project.name, title, timestamp, level, release, environment, server_name, the three user columns, and count() as the one aggregate - and a field outside it answers an explicit 400 with the coverage pointer rather than a silent null (invariant #4). Sentry's structured search grammar is not parsed, so a non-empty `query` is refused rather than ignored", mode_reviewed: "2026-09-12", tag: "Discover" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/integrations/", area: "integrations", tier: 3, status: "green", mode: "empty", mode_reason: "verbatim the fact `sentry-app-installations/` was already ruled on, at the other of the two addresses Sentry publishes it from: canon carries no app or integration install row of ANY kind, and integrationsFor() is PagerDuty's inbound alert route over a deliberately fictional vendor catalogue - a different provider's entity in a different domain; Sentry's own answer for an organization with none installed is `[]` at 200. RULED by the founder 2026-09-12 on the unclassified sweep's proposal, as proposed.", mode_reviewed: "2026-09-12", tag: "Integrations" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/issues/{issue_id}/", area: "issues", tier: 1, status: "green", mode: "derive", tag: "Events" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/issues/{issue_id}/events/", area: "issues", tier: 1, status: "green", mode: "derive", tag: "Events" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/issues/{issue_id}/events/latest/", area: "issues", tier: 1, status: "green", mode: "derive", tag: "Events" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/issues/{issue_id}/events/oldest/", area: "issues", tier: 1, status: "green", mode: "derive", tag: "Events" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/issues/{issue_id}/hashes/", area: "issues", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12: a grouping hash is a digest of the SIGNATURE events were grouped on, and canon's signature is the pair the generator deduplicated by (the exception type and the culprit path) - so a canonical ErrorGroup has exactly one hash, derived by ids.ts's existing hex derivation. `latestEvent` is the group's newest shaped event, the same one events/latest/ serves", mode_reviewed: "2026-09-12", tag: "Events" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/issues/{issue_id}/tags/{key}/", area: "issues", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12: eventTags() already computes the whole tag vocabulary per event from canon (level, server_name, environment, release), so `totalValues` is a count over the group's own events. A key no event of the group carries is Sentry's own 404 - a tag key exists because events have it", mode_reviewed: "2026-09-12", tag: "Events" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/issues/{issue_id}/tags/{key}/values/", area: "issues", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12: the same per-event tag list eventTags() computes, de-duplicated over the group's events and sorted. No field outside eventTags is required", mode_reviewed: "2026-09-12", tag: "Events" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/members/", area: "organizations", tier: 1, status: "green", mode: "derive", tag: "Organizations" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/members/{member_id}/", area: "organizations", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (the unclassified sweep): the roster's own row, by the id the roster publishes. The operation's 200 IS the component OrganizationMemberWithRoles, which is the list item plus six required fields, and every one of them was already a fact this host holds - `teams` and `teamRoles` are reader.teamMembers(), the same edge /teams/{org}/{team}/members/ has paged since M2 and which the suite now walks in BOTH directions; `isOnlyOwner` is computed off the roster rather than asserted (nobody holds `owner`, so nobody is the only one who does, and the day canon grows an owner the answer moves); `invite_link` is null, the same fact the green list row states as `inviterName: null`. The two ROLE CATALOGS are the only values here that are not an artifact row: they are Sentry's own vocabulary, copied verbatim out of the vendored description's worked example (openapi-derefed.json, the UpdateAnOrganization example), and the conformance case reads that example back out of the document and reds the row if the served bytes differ by so much as a scope string - so the copy is evidence rather than invention and cannot rot. teamRoles[].role is the catalog's own `minimumTeamRole` for the org role the member holds, looked up rather than chosen, because canon assigns nobody an explicit team role and the schema types `role` as a required non-nullable string", mode_reviewed: "2026-09-12", tag: "Organizations" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/monitors/", area: "crons", tier: 2, status: "green", mode: "empty", mode_reason: "no cron monitor is configured in this Sentry organization - the served project object says so (SURFACE_FLAGS.hasMonitors=false, render.ts:166); canon's `monitor` table (14) is a METRIC threshold monitor (series/comparison/threshold/for_sec) with no schedule, and the one scheduled job in the universe (workflow_schedule, a nightly on repo-01) belongs to no service and so has no Sentry project to be monitored in; Sentry's own answer for an organization with none is `[]` at 200; RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Crons" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/monitors/{monitor_id_or_slug}/", area: "crons", tier: 2, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the empty beside it: .../monitors/ serves `[]` on this same host, so no id or slug can name a cron monitor and Sentry's own 404 is the whole answer; RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Crons" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/monitors/{monitor_id_or_slug}/checkins/", area: "crons", tier: 2, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the same empty: with no cron monitor, no monitor id resolves and there is nothing to check in against; RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Crons" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/notifications/actions/", area: "alerts", tier: 2, status: "deferred", mode: "unclassified", tag: "Alerts" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/notifications/actions/{action_id}/", area: "alerts", tier: 2, status: "deferred", mode: "unclassified", tag: "Alerts" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/projects/", area: "organizations", tier: 1, status: "green", mode: "derive", tag: "Organizations" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/relay_usage/", area: "organizations", tier: 1, status: "green", mode: "empty", mode_reason: "no Sentry Relay is deployed in this organization - every error event is recorded directly against a project (error_event.service, 85 rows) and canon carries no relay entity at all; Sentry's own answer for an organization with no registered relay is `[]` at 200; RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Organizations" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/release-threshold-statuses/", area: "releases", tier: 1, status: "green", mode: "empty", mode_reason: "no release threshold is configured on any project in this universe - canon's Release (3) carries a tag, a commit, an author and a body and no threshold rule; Sentry's own answer for an organization with none is an empty object at 200; RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Releases" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/releases/", area: "releases", tier: 1, status: "green", mode: "derive", tag: "Releases" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/releases/{version}/", area: "releases", tier: 1, status: "green", mode: "derive", tag: "Releases" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/releases/{version}/commitfiles/", area: "releases", tier: 1, status: "planned", mode: "unclassified", tag: "Releases" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/releases/{version}/commits/", area: "releases", tier: 1, status: "green", mode: "derive", tag: "Releases" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/releases/{version}/deploys/", area: "releases", tier: 1, status: "green", mode: "derive", tag: "Releases" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/releases/{version}/files/", area: "releases", tier: 1, status: "green", mode: "empty", mode_reason: "no release in this universe uploads release artifacts - every project is the `node` platform (render.ts:161, read off the file model) deployed from the git repository, and nothing here runs `sentry-cli releases files upload`; Sentry's own answer for a release with no files is `[]` at 200; RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Releases" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/releases/{version}/files/{file_id}/", area: "releases", tier: 1, status: "planned", mode: "refuse", mode_reason: "ENTAILED by the empty beside it: .../releases/{version}/files/ serves `[]` on this same host, so no file id can name a release artifact and Sentry's own 404 for this operation is the whole answer (the agents/{id} precedent, MODES.yaml 2026-09-06); RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Releases" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/replay-count/", area: "replays", tier: 3, status: "green", mode: "empty", mode_reason: "Session Replay is not enabled for any project in this universe - the served project object says so (SURFACE_FLAGS.hasReplays=false, render.ts:166) and canon carries no replay, click or recording-segment row; Sentry's own answer for a count query with no replays is an object of zeros at 200; RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Replays" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/replay-selectors/", area: "replays", tier: 3, status: "green", mode: "empty", mode_reason: "the same fact: no replay exists, so no DOM selector was ever recorded (SURFACE_FLAGS.hasReplays=false); Sentry's own answer is `{data: []}` at 200; RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Replays" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/replays/", area: "replays", tier: 3, status: "green", mode: "empty", mode_reason: "no replay exists in this universe - the served project object already asserts hasReplays=false (render.ts:166) and no canonical entity records a session recording; Sentry's own answer for an organization with none is `[]` at 200; RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Replays" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/replays/{replay_id}/", area: "replays", tier: 3, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the empty beside it: .../replays/ serves `[]`, so no replay id resolves and Sentry's own 404 is the whole answer; RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Replays" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/repos/", area: "organizations", tier: 1, status: "green", mode: "derive", tag: "Organizations" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/repos/{repo_id}/commits/", area: "organizations", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12: required id/message/dateCreated IS the object shapeReleaseCommit already returns for /releases/{version}/commits/, over reader.listCommits(repo) rather than one release's range. The {repo_id} resolves against the ids /organizations/{org}/repos/ already publishes", mode_reviewed: "2026-09-12", tag: "Organizations" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/scim/v2/Groups", area: "scim", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12: the `SCIM is not enabled, so 403` reading is FALSIFIED by the artifact - identity_provider_config carries protocol=saml with scim_enabled=1 from hello-15 on. A SCIM Group IS a Sentry team (the sibling path parameter is literally {team_id}) and `displayName` is the team SLUG, which is what the vendored example's own slug-shaped value carries. Generation-gated: an artifact predating features.ciConfig names hello-15 rather than serving an empty directory", mode_reviewed: "2026-09-12", tag: "SCIM" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/scim/v2/Groups/{team_id}", area: "scim", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12: one group by the same team id /organizations/{org}/teams/ already serves; displayName is the team slug and members are the real team members. Generation-gated on features.ciConfig (hello-15), like the list beside it", mode_reviewed: "2026-09-12", tag: "SCIM" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/scim/v2/Users", area: "scim", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12: a SCIM User is an org member addressed by the MEMBER id the path parameter names, which /organizations/{org}/members/ has served as a `derive` row since 2026-09-01. `sentryOrgRole` is orgRoleFor(), the one mapping this renderer already makes, so the directory and the member list cannot disagree. Generation-gated on features.ciConfig (hello-15)", mode_reviewed: "2026-09-12", tag: "SCIM" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/scim/v2/Users/{member_id}", area: "scim", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12: the same resource by member id. `name` splits the canonical name on its first space; a persona with one name has an EMPTY familyName, which is the absence expressed in the field's own type rather than Sentry's own `N/A` placeholder (invariant #4). Generation-gated on features.ciConfig (hello-15)", mode_reviewed: "2026-09-12", tag: "SCIM" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/sentry-app-installations/", area: "integrations", tier: 3, status: "green", mode: "empty", mode_reason: "no Sentry app is installed in this organization - canon carries no app or integration install row of any kind and this replica serves no /sentry-apps/ surface for one to be installed from; Sentry's own answer for an organization with none is `[]` at 200; RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Integration" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/sessions/", area: "releases", tier: 1, status: "green", mode: "empty", mode_reason: "no SDK in this universe reports release-health sessions - the served project object already says so (SURFACE_FLAGS.hasSessions=false, render.ts:166) and canon carries no session counter; Sentry's own answer for an organization with no session data is a 200 whose `groups` is `[]` over real intervals; RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Releases" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/shortids/{short_id}/", area: "organizations", tier: 1, status: "green", mode: "derive", tag: "Organizations" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/stats_v2/", area: "organizations", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12: every canonical error_event is one accepted `error` outcome at a real instant, so the series is a bucket count over error_event.t_epoch grouped by project/category/outcome. The window ends at the artifact's ANCHOR, never at a wall clock (invariant #1), and a caller who names no period gets the artifact's own window - the only default this host can claim provenance for. A category or outcome this universe never ingested selects nothing", mode_reviewed: "2026-09-12", tag: "Organizations" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/stats-summary/", area: "organizations", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12: the same bucket count over error_event.t_epoch, rolled up per project rather than per interval. The five drop columns (filtered, rate_limited, invalid, abuse, client_discard, cardinality_limited) are zero because this universe records no rejected ingest at all - there is no ingest, the events were generated - and saying so is what stops a caller reading a drop rate off a number nothing supports", mode_reviewed: "2026-09-12", tag: "Organizations" }
      - { method: "GET", path: "/api/0/organizations/{organization_id_or_slug}/teams/", area: "teams", tier: 1, status: "green", mode: "derive", tag: "Teams" }
      - { method: "GET", path: "/api/0/projects/", area: "projects", tier: 1, status: "green", mode: "derive", tag: "Projects" }
      - { method: "GET", path: "/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/", area: "projects", tier: 1, status: "green", mode: "derive", tag: "Projects" }
      - { method: "GET", path: "/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/events/", area: "issues", tier: 1, status: "green", mode: "derive", tag: "Events" }
      - { method: "GET", path: "/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/events/{event_id}/", area: "issues", tier: 1, status: "green", mode: "derive", tag: "Events" }
      - { method: "GET", path: "/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/events/{event_id}/source-map-debug/", area: "issues", tier: 1, status: "green", mode: "empty", mode_reason: "no event in this universe has a minified frame to unminify - the served project object says so (SURFACE_FLAGS.hasMinifiedStackTrace=false, render.ts:166) and every error_frame (51) resolves to a real file in the repository tree at the group's resolved_sha, with the real source lines served as the frame's `context`; Sentry's own answer when it finds no problem is `{errors: []}` at 200; RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Events" }
      - { method: "GET", path: "/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/files/dsyms/", area: "projects", tier: 1, status: "green", mode: "empty", mode_reason: "no debug information file is uploaded by any project here - every project is the `node` platform (render.ts:161) and a Node project produces no dSYM or PDB to upload; Sentry's own answer for a project with none is `[]` at 200; RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Projects" }
      - { method: "GET", path: "/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/hooks/", area: "projects", tier: 1, status: "green", mode: "empty", mode_reason: "no service hook is registered on any project in this universe - canon's webhook_subscription rows are the incident-alerting subscriptions (filter_kind account/service/team, delivery_url hooks.olympus-labs.dev) and, from hello-18's webhookFilters, the repository, organization and namespace hooks a repository host publishes - and no row of either kind is a Sentry project hook (clause re-worded at the hello-18 cutover 2026-09-12: the canon grew, the conclusion did not move); Sentry's own answer for a project with none is `[]` at 200; RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Projects" }
      - { method: "GET", path: "/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/hooks/{hook_id}/", area: "projects", tier: 1, status: "planned", mode: "refuse", mode_reason: "ENTAILED by the empty beside it: .../hooks/ serves `[]` on this same host, so no hook id can name a service hook and Sentry's own 404 is the whole answer; RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Projects" }
      - { method: "GET", path: "/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/issues/", area: "issues", tier: 1, status: "green", mode: "derive", tag: "Events" }
      - { method: "GET", path: "/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/keys/", area: "projects", tier: 1, status: "planned", mode: "generate", mode_reason: "NEW CANON ENTITY SentryProjectKey, and NOT a widening: no client key, public key, secret, ingest host or DSN exists in any table or any generation, and person_credential's nine kinds are PEOPLE'S keys - ssh, gpg, email, social, personal, project, group and deploy tokens - rather than a project's ingest key. The blocker is the opposite way round from this provider's other tier-1 gap: the schema is complete (component ProjectKey) and it is the canon that is absent. `dsn` is REQUIRED with all nine sub-fields required non-nullable strings (cdn, crons, csp, minidump, nel, public, secret, security, unreal), so nothing here can be honestly nulled and no field may be omitted. The render-time minting precedent exists - PagerDuty's derivedRoutingKey, CircleCI's masked tail - but is strictly smaller than nine DSN URLs carrying a user:password@host shape, which is why the answer is a table rather than a mint, and the standing credentials ruling is that canon holds a public half whose private half was never generated. Priced at ~11 KB by the 2026-09-12 W1 wave. It unblocks TWO rows, both TIER 1, both on this provider. CLASSIFIED 2026-09-13 (the unjudged-47 pass) on the 2026-09-12 sweep's proposal", mode_reviewed: "2026-09-13", tag: "Projects" }
      - { method: "GET", path: "/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/keys/{key_id}/", area: "projects", tier: 1, status: "planned", mode: "generate", mode_reason: "one client key by id, blocked by the same absent SentryProjectKey table as the list beside it; the same ~11 KB entity unblocks both. CLASSIFIED 2026-09-13 (the unjudged-47 pass)", mode_reviewed: "2026-09-13", tag: "Projects" }
      - { method: "GET", path: "/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/monitors/{monitor_id_or_slug}/", area: "crons", tier: 2, status: "deferred", mode: "refuse", mode_reason: "the project-scoped route to the same non-existent monitor; entailed by the org-scoped `[]`; RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Crons" }
      - { method: "GET", path: "/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/monitors/{monitor_id_or_slug}/checkins/", area: "crons", tier: 2, status: "deferred", mode: "refuse", mode_reason: "the project-scoped route to the same non-existent monitor's check-ins; entailed by the org-scoped `[]`; RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Crons" }
      - { method: "GET", path: "/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/ownership/", area: "projects", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12: `raw` is the repository's own .github/CODEOWNERS, byte for byte out of the tree, and schema.rules is that text parsed - every principal in it is a team /organizations/{org}/teams/ serves (invariant #5). The four required settings are stated judgments: isActive and codeownersAutoSync are facts about the FILE (it exists and is re-read from the tree on every request), while fallthrough=false and autoAssignment=`Turn off Auto-Assignment` are absences of SENTRY-side configuration - the second corroborated by shapeIssue's assignedTo, which is the incident commander and never an owner. Generation-gated on features.repoOwnership (hello-17)", mode_reviewed: "2026-09-12", tag: "Projects" }
      - { method: "GET", path: "/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/releases/{version}/commits/", area: "releases", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12: the project-scoped twin of /organizations/{org}/releases/{version}/commits/, which has been `derive` since 2026-09-01 - same rows, same shaper, narrower scope (the release must be one this project ships)", mode_reviewed: "2026-09-12", tag: "Releases" }
      - { method: "GET", path: "/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/releases/{version}/files/", area: "releases", tier: 1, status: "green", mode: "empty", mode_reason: "the project-scoped half of the same fact: no release in this universe uploads release artifacts (every project is `node`, deployed from git, and nothing runs `sentry-cli releases files upload`); Sentry's own answer is `[]` at 200; RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Releases" }
      - { method: "GET", path: "/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/releases/{version}/files/{file_id}/", area: "releases", tier: 1, status: "planned", mode: "refuse", mode_reason: "ENTAILED by the empty beside it: the project-scoped file list serves `[]`, so no file id resolves and Sentry's own 404 is the whole answer; RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Releases" }
      - { method: "GET", path: "/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/replays/{replay_id}/clicks/", area: "replays", tier: 3, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the replay empty: no replay id resolves on this host, so Sentry's own 404 is the whole answer; RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Replays" }
      - { method: "GET", path: "/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/replays/{replay_id}/recording-segments/", area: "replays", tier: 3, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the replay empty: no replay id resolves, so there is no recording to segment; RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Replays" }
      - { method: "GET", path: "/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/replays/{replay_id}/recording-segments/{segment_id}/", area: "replays", tier: 3, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the replay empty: neither the replay id nor a segment index inside it resolves; RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Replays" }
      - { method: "GET", path: "/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/replays/{replay_id}/viewed-by/", area: "replays", tier: 3, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the replay empty: no replay id resolves, so nobody can have viewed one; RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Replays" }
      - { method: "GET", path: "/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/rules/", area: "alerts", tier: 2, status: "green", mode: "empty", mode_reason: "no issue-alert rule was ever created on any project here - canon's `monitor` is a METRIC threshold (series, comparison, threshold, for_sec) and not an issue rule, and every required field of Sentry's `Rule` but `id` and `projects` is configuration this universe never made: `conditions`, `filters` and `actions` carry Sentry's own internal class paths; Sentry's own answer for a project with none is `[]` at 200. RULED by the founder 2026-09-12 on the unclassified sweep's proposal, as proposed.", mode_reviewed: "2026-09-12", tag: "Alerts" }
      - { method: "GET", path: "/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/rules/{rule_id}/", area: "alerts", tier: 2, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the empty beside it: the project's rule list serves `[]` on this same host, so no rule id resolves and Sentry's own 404 is the whole answer. RULED by the founder 2026-09-12 on the unclassified sweep's proposal, as proposed.", mode_reviewed: "2026-09-12", tag: "Alerts" }
      - { method: "GET", path: "/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/stats/", area: "projects", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12: the response is an array of [timestamp, count] pairs with no required object field, and the counts are real buckets over error_event.t_epoch for the service the project IS. The default grid is the 24 hourly buckets the vendored example carries, ending at the artifact's ANCHOR; `rejected` and `blacklisted` are zero everywhere because this universe records no rejected ingest", mode_reviewed: "2026-09-12", tag: "Projects" }
      - { method: "GET", path: "/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/symbol-sources/", area: "projects", tier: 1, status: "green", mode: "empty", mode_reason: "no custom symbol source is configured on any project here - canon carries no symbol server and every project is the `node` platform, which has no native symbols to fetch; Sentry's own answer for a project with none is `[]` at 200; RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Projects" }
      - { method: "GET", path: "/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/tags/{key}/values/", area: "projects", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12: required `name` only - the project-scoped de-duplication of the same per-event tag list the issue-scoped twin aggregates", mode_reviewed: "2026-09-12", tag: "Projects" }
      - { method: "GET", path: "/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/teams/", area: "teams", tier: 1, status: "green", mode: "derive", tag: "Teams" }
      - { method: "GET", path: "/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/user-feedback/", area: "projects", tier: 1, status: "green", mode: "empty", mode_reason: "nobody has submitted user feedback in this universe - the served project object says so (SURFACE_FLAGS.hasFeedbacks=false and hasNewFeedbacks=false, render.ts:166) and canon's error events are SDK-reported with no attached report; Sentry's own answer for a project with none is `[]` at 200; RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Projects" }
      - { method: "GET", path: "/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/users/", area: "projects", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12: required username+email only, and eventUser() already shapes exactly those two fields from error_event.person. An event the canon recorded no person for contributes nobody rather than a row of nulls, and every address joins to a canonical person under the org-wide convention every provider in the fleet shares", mode_reviewed: "2026-09-12", tag: "Projects" }
      - { method: "GET", path: "/api/0/teams/{organization_id_or_slug}/{team_id_or_slug}/", area: "teams", tier: 1, status: "green", mode: "derive", tag: "Teams" }
      - { method: "GET", path: "/api/0/teams/{organization_id_or_slug}/{team_id_or_slug}/members/", area: "teams", tier: 1, status: "green", mode: "derive", tag: "Teams" }
      - { method: "GET", path: "/api/0/teams/{organization_id_or_slug}/{team_id_or_slug}/projects/", area: "teams", tier: 1, status: "green", mode: "derive", tag: "Teams" }
      - { method: "GET", path: "/api/0/teams/{organization_id_or_slug}/{team_id_or_slug}/stats/", area: "teams", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12: the same [timestamp, count] array as the project stats, summed over the services the team owns (service.team) - the set /teams/{org}/{team}/projects/ already resolves", mode_reviewed: "2026-09-12", tag: "Teams" }
    graphql: [] # no GraphQL API exists for this provider (REST-only)
  circleci:
    rest:
      - { method: "GET", path: "/context", area: "contexts", tier: 2, status: "green", mode: "derive", mode_reason: "the founder ruled this row and eighteen siblings on 2026-09-05, re-ruling B2.1's proposed empty: data is the product, so fulfil the contract. SERVED — and `derive` rather than `generate` is the accurate label, because the response is computed from artifact rows that already exist: one context per distinct `deployment.environment`, created at the earliest canonical deployment to it. No new canon and no new words — `staging` and `production` are structural canon strings, not themed prose", mode_reviewed: "2026-09-05", tag: "Context" }
      - { method: "GET", path: "/context/{context_id}", area: "contexts", tier: 2, status: "green", mode: "derive", mode_reason: "the same derivation addressed by id (founder ruling 2026-09-05). A well-formed uuid naming no context answers the document's own `context_not_found` sentence; an id that is not a uuid answers `400_invalid_context_id`", mode_reviewed: "2026-09-05", tag: "Context" }
      - { method: "GET", path: "/context/{context_id}/environment-variable", area: "contexts", tier: 2, status: "green", mode: "derive", mode_reason: "one variable per row of the canonical VENDOR_CATALOG - the third-party credentials a deploy job carries, named from vendor names the theme baked in at compile time, so no real company is named and no word is authored in the renderer. THE OPERATION PUBLISHES NO VALUES AT ALL: `env_var_list` declares variable/created_at/updated_at/context_id and nothing else, which is CircleCI's own posture on context credentials (founder ruling 2026-09-05)", mode_reviewed: "2026-09-05", tag: "Context" }
      - { method: "GET", path: "/context/{context_id}/restrictions", area: "contexts", tier: 2, status: "green", mode: "derive", mode_reason: "a `project` restriction naming the canonical project by the same id /project/{project-slug} prints, so the reference resolves on this host. `project` is the only one of CircleCI's three restriction kinds this canon can state - `expression` carries OPA source text and `group` names an SSO identity group, which B2.1 already ruled generate (founder ruling 2026-09-05)", mode_reviewed: "2026-09-05", tag: "Context" }
      - { method: "GET", path: "/deploy/components", area: "deploy", tier: 2, status: "green", mode: "derive", mode_reason: "one row per canonical Component this repository has really shipped: `reader.listDeployments` gives the rollouts, `reader.getCommitById` gives each one's commit, and the commit names the Component it changed - so `name` is `reader.componentSlug` of that id, the same slug renderer-github prints inside every changed file's path. `release_count` is the number of those deployments, which makes it the length of the /versions list by construction rather than by coincidence. `labels` is an honest empty (canon labels nothing here) and `org-id` and `page-size` are both declared REQUIRED, so a request without either is not one this operation accepts", mode_reviewed: "2026-09-09", tag: "Deploy" }
      - { method: "GET", path: "/deploy/components/{component_id}", area: "deploy", tier: 2, status: "green", mode: "derive", mode_reason: "the same derivation addressed by id, asserted byte-identical to the row the list prints so the two addressings of one component cannot drift. An id that names no component this org has deployed answers `404_entity_not_found`'s own description, `Entity not found.` - the document exemplifies six entity kinds and a deploy component is not one of them, so the sentence is the shared response's rather than a plausible-looking one this host would be inventing", mode_reviewed: "2026-09-09", tag: "Deploy" }
      - { method: "GET", path: "/deploy/components/{component_id}/versions", area: "deploy", tier: 2, status: "green", mode: "derive", mode_reason: "one version per canonical Deployment of that component. `name` is the release TAG when the deployment shipped one (`reader.listReleases`; production deployments carry `ref = tag`) and the deployed commit's short sha otherwise - 16 of this universe's 19 deployments are staging rollouts whose `ref` is the default branch, and publishing `main` as a version name would give every one of them the same name. `is_live` is the newest SUCCEEDED deployment per environment, so a failed or still-queued rollout is in the list and is not live. FOUR FIELDS ARE DELIBERATELY ABSENT rather than filled: `namespace` (canon models no orchestrator) and `pipeline_id`/`workflow_id`/`job_id`/`job_number` - canon says a deployment is caused by a MERGE or a RELEASE, never by a run (generateDeployments), so naming the release-workflow run that happens to share the commit would assert a causal link this universe does not contain. Every property of the schema is optional, so absence is the document's own way of saying so. The operation declares NO page-token and NO page-size, so `next_page_token` is always null: issuing one would name a parameter the operation cannot accept", mode_reviewed: "2026-09-09", tag: "Deploy" }
      - { method: "GET", path: "/deploy/environments", area: "deploy", tier: 2, status: "green", mode: "derive", mode_reason: "one environment per distinct `Deployment.environment` off `reader.listDeployments`, created at the earliest deployment to it and updated at the latest - THE SAME DERIVATION `GET /context` has published since 2026-09-05, and conformance asserts the two lists are the same length so one column cannot produce two different answers. `description` is ABSENT because canon gives an environment no prose; `labels` is an honest empty. `org-id` and `page-size` are declared REQUIRED and are enforced, and the caller's `page-size` is the page size this host uses rather than its own PAGE_SIZE", mode_reviewed: "2026-09-09", tag: "Deploy" }
      - { method: "GET", path: "/deploy/environments/{environment_id}", area: "deploy", tier: 2, status: "green", mode: "derive", mode_reason: "the same derivation addressed by id, asserted byte-identical to the row the list prints. A well-formed uuid naming no environment answers the shared entity 404; an id that is not a uuid answers the operation's own 400, the same split the context and schedule families already make on this host", mode_reviewed: "2026-09-09", tag: "Deploy" }
      - { method: "GET", path: "/insights/{org-slug}/summary", area: "insights", tier: 2, status: "green", mode: "derive", mode_reason: "totals over every repository's `reader.listRuns`, with duration read off each run's start and completion. THE ONE VALUE THAT IS NOT AN AGGREGATE IS CREDITS, and it is derived rather than zeroed or omitted: canon states the resource class (packages/compiler/src/files.ts writes `resource_class: medium` under a docker executor, and CircleCI's own default for a docker executor that declares none is medium too), and 10 credits/minute is CircleCI's published rate for docker/medium - so credits are whole minutes of job wall time at the vendor's list price, the same pin-scoped price-table shape renderer-anthropic and renderer-openai already use for token cost. `0` would be false and the field is required and not nullable. TRENDS ARE RELATIVE CHANGE against the same-length window immediately before, one rule for all nine floats because the document defines none; this universe's canon is exactly 90 days, so every trend on the default `last-90-days` window is 0 for want of a baseline and a caller asking for `last-7-days` gets real movement - conformance asserts both halves so the zeros read as arithmetic rather than as a stub. `all_projects` stays unfiltered when `project-names` narrows the rows", mode_reviewed: "2026-09-09", tag: "Insights" }
      - { method: "GET", path: "/insights/{project-slug}/branches", area: "insights", tier: 2, status: "green", mode: "derive", mode_reason: "the branch of every canonical pipeline this project has, taken from the renderer's own model rather than from `reader.listBranches` - the field's description is `the VCS branch of a WORKFLOW'S TRIGGER`, so the list is the branches CircleCI has really seen build, not every branch the repository carries. Conformance asserts both: each served branch is a branch a pipeline was built on AND a branch the repository really has. `workflow-name` narrows to the branches that workflow ran on (the release workflow only ever ran on the default branch, which is what makes the filter checkable); a workflow this project does not have is an ENTITY miss and carries no coverage header", mode_reviewed: "2026-09-09", tag: "Insights" }
      - { method: "GET", path: "/insights/{project-slug}/flaky-tests", area: "insights", tier: 2, status: "green", mode: "derive", mode_reason: "hello-15's TestCase/TestResult made this derivable and the derivation is CircleCI's own published definition, quoted: a flaky test is one that PASSED AND FAILED IN THE SAME COMMIT. The nightly is what makes it visible - this universe has main-line commits on 41 of its 90 days, so on 49 nights the schedule recompiles the sha it compiled the night before, which is the situation a flake shows up in and the reason real orgs find theirs in the nightly. Nothing is labelled flaky in canon: `flakiness` is a per-run rate the generator rolls against, and this row derives the OUTCOME from the results, exactly as the coherence suite does. `file` is null because canon states none (DECISIONS 2026-09-06 judgment 3), `source` is `junit` because canon states the report IS JUnit XML - ARTIFACT_MIME serves it as application/xml and JUNIT_BYTES_PER_CASE derives its size from the case count", mode_reviewed: "2026-09-07", tag: "Insights" }
      - { method: "GET", path: "/insights/{project-slug}/workflows", area: "insights", tier: 2, status: "green", mode: "derive", mode_reason: "one row per canonical Workflow that RAN inside the reporting window, over `reader.listRuns` and `reader.runJobs`. A workflow with no run in the window is ABSENT rather than present with zeroes: it has no metrics to report and no first build to name. `mttr` is the mean interval from a failing run's completion to the completion of the next run of the same workflow that succeeded - a failure with no later success has not recovered and is not averaged in, and `null` when none has. `duration_metrics.p95` is nearest-rank, the same definition the test-metrics row uses, so the two insights families cannot report a percentile two different ways. Credits are the docker/medium rate insights.ts documents", mode_reviewed: "2026-09-09", tag: "Insights" }
      - { method: "GET", path: "/insights/{project-slug}/workflows/{workflow-name}", area: "insights", tier: 2, status: "green", mode: "derive", mode_reason: "the workflow's runs themselves, newest first, off `reader.listRuns`. Every `id` is the renderer's own `workflowId`, so conformance follows it to `GET /workflow/{id}` and asserts the two surfaces agree about the run (invariant #5). `branch` is the branch its pipeline was built on - the same derivation `GET /pipeline` prints, never a second copy. `is_approval` is false on every run because an approval is a MANUAL HOLD this canon has no entity for, the same fact `shapeWorkflowJob` states by emitting `type: build` on every job. `start-date`/`end-date` bound the window directly and an `end-date` without a `start-date` is refused, because the document says one must accompany the other", mode_reviewed: "2026-09-09", tag: "Insights" }
      - { method: "GET", path: "/insights/{project-slug}/workflows/{workflow-name}/jobs", area: "insights", tier: 2, status: "green", mode: "derive", mode_reason: "the same metric object one level down, over the `reader.runJobs` of that workflow's runs, grouped by job NAME - which is what the operation's items are keyed on. A WORKFLOW'S CREDITS ARE ITS JOBS' CREDITS by construction and conformance asserts the two rows agree, so this host cannot serve one bill two ways. `job-name` narrows to a single row", mode_reviewed: "2026-09-09", tag: "Insights" }
      - { method: "GET", path: "/insights/{project-slug}/workflows/{workflow-name}/summary", area: "insights", tier: 2, status: "green", mode: "derive", mode_reason: "the same aggregates for one workflow, plus the trends against the preceding window and the project's full workflow list. Conformance asserts field-by-field that this row and the `/workflows` list carry the SAME numbers for the same workflow - two surfaces over one derivation, not two derivations. `completed_runs` equals `total_runs` and that is a fact about this canon rather than a field copied from its neighbour: every canonical WorkflowRun carries a completion instant and a terminal conclusion. This operation declares no `reporting-window`, so it reports on the document's own 90-day default", mode_reviewed: "2026-09-09", tag: "Insights" }
      - { method: "GET", path: "/insights/{project-slug}/workflows/{workflow-name}/test-metrics", area: "insights", tier: 2, status: "green", mode: "derive", mode_reason: "the same TestResult canon, aggregated per workflow. `test_counts` uses canon's FOUR statuses rather than a JUnit summary's three - `error` (the suite fell over) and `failure` (an assertion failed) are different facts and canon takes the finer set so a renderer can collapse and never invent. `p95_duration` is nearest-rank over the case's real durations, the definition that needs no interpolation and therefore no choice; `flaky` is the same derivation the sibling row publishes, so the two surfaces cannot disagree about which tests flake", mode_reviewed: "2026-09-07", tag: "Insights" }
      - { method: "GET", path: "/insights/pages/{project-slug}/summary", area: "insights", tier: 2, status: "green", mode: "derive", mode_reason: "the same aggregates one level down: the project, each of its Workflows, and each (Workflow, branch) pair, over `reader.listRuns` and `reader.runJobs` with the branch taken from the renderer's own pipeline model. Conformance asserts the three levels RECONCILE - the workflow rows sum to the project's runs and so do the (workflow, branch) rows - which is what makes this a view of one fact rather than three. `all_branches` and `all_workflows` stay UNFILTERED when `branches`/`workflow-names` narrow the rows, because they are the lists the filters are chosen from. THE SLUG SITS BEHIND A LITERAL here, so the escaped-slug rewrite counts its two separators from `/api/v2/insights/pages/` rather than from `/api/v2/insights/`; counting from the shorter prefix spends one separator on the `/` after `pages` and 404s the escaped spelling, and both spellings are asserted over real HTTP", mode_reviewed: "2026-09-09", tag: "Insights" }
      - { method: "GET", path: "/insights/time-series/{project-slug}/workflows/{workflow-name}/jobs", area: "insights", tier: 2, status: "green", mode: "derive", mode_reason: "one bucket per (job name, interval) over `reader.runJobs`, the interval floored on the UTC epoch so no calendar and no timezone is involved. THE RETENTION IS THE PROVIDER'S OWN, mirrored rather than invented: the operation says hourly data is kept 48 hours and daily 90 days, so an hourly request reports the 48 hours ending at this artifact's anchor and a daily one its 90 days. `branch` defaults to the DEFAULT BRANCH because the document says it does. `name` is the JOB's name - the operation is getJobTimeseries and its summary says `all jobs within a workflow`, while the field's description is the workflow item's copied verbatim; the discrepancy is recorded in insights.ts rather than quietly resolved", mode_reviewed: "2026-09-09", tag: "Insights" }
      - { method: "GET", path: "/jobs/{job_id}", area: "jobs", tier: 1, status: "green", mode: "derive", tag: "Job" }
      - { method: "GET", path: "/me", area: "users", tier: 1, status: "green", mode: "derive", tag: "User" }
      - { method: "GET", path: "/me/collaborations", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "the org roster IS the collaboration list, and Collaboration.avatar_url is the organization's avatar ON THE VCS - gh.sandboxapis.dev/avatars/o/{id}, built with renderer-github's own githubId rather than a second copy of the hash", mode_reviewed: "2026-09-07", tag: "User" }
      - { method: "GET", path: "/org/{orgID}/oidc-custom-claims", area: "oidc", tier: 3, status: "green", mode: "derive", mode_reason: "hello-15's OidcClaimConfiguration. The org-scoped row is the one with no project, which is what makes it distinguishable from the project override beside it. `ttl` is formatted into Go's duration grammar because the document types it as a STRING (`JSONDuration`) rather than a number of seconds", mode_reviewed: "2026-09-07", tag: "OIDC Token Management" }
      - { method: "GET", path: "/org/{orgID}/project/{projectID}/oidc-custom-claims", area: "oidc", tier: 3, status: "green", mode: "derive", mode_reason: "OidcClaimConfiguration at project scope. ABSENT IS MEANINGFUL: a project with no override inherits the org row, so answering with the org row here would make the two endpoints indistinguishable - the reader keeps `orgOidcClaims` and `projectOidcClaims` apart for exactly this reason and a project with no override answers the entity 404", mode_reviewed: "2026-09-07", tag: "OIDC Token Management" }
      - { method: "GET", path: "/organization/{org-slug-or-id}", area: "organizations", tier: 1, status: "green", mode: "derive", tag: "Organization" }
      - { method: "GET", path: "/organization/{org-slug-or-id}/url-orb-allow-list", area: "organizations", tier: 1, status: "green", mode: "derive", mode_reason: "hello-15's UrlOrbSource. The 2026-09-05 reason was that `every candidate prefix would be a URL that 404s on gh.sandboxapis.dev (invariant #5)`, so the entity carries NO PREFIX AT ALL - repository, branch and directory - and the compiler writes a genuine orb document into that directory in that repository's tree. The renderer composes the prefix from names the artifact already carries, in GitHub's own contents-API shape, and `ci-parity` FETCHES the orb document from the gh host and asserts it answers 200. The URL resolves because the file is there (DECISIONS 2026-09-06)", mode_reviewed: "2026-09-07", tag: "Organization" }
      - { method: "GET", path: "/organizations/{org_id}/groups", area: "groups", tier: 3, status: "green", mode: "derive", mode_reason: "hello-15's IdentityGroup, and the canon answers the objection this row was refused for. The 2026-09-05 reason was that mapping a Team onto an SSO group `would assert an SSO configuration nobody made`; hello-15 MAKES the configuration (IdentityProviderConfig - a protocol, a date and an administrator) and derives four groups from access facts rather than from team membership. Both canon suites assert no group has exactly a team's membership and that at least one crosses team boundaries, so the two entities stay distinct", mode_reviewed: "2026-09-07", tag: "Groups" }
      - { method: "GET", path: "/organizations/{org_id}/groups/{group_id}", area: "groups", tier: 3, status: "green", mode: "derive", mode_reason: "the same IdentityGroup by id. MEMBERS ARE NOT INCLUDED - the document says so on this operation, and the list item carries the same three fields, so neither addressing publishes the membership canon records", mode_reviewed: "2026-09-07", tag: "Groups" }
      - { method: "GET", path: "/organizations/{org_id}/usage_export_job/{usage_export_job_id}", area: "usage", tier: 3, status: "deferred", mode: "refuse", mode_reason: "a usage export job is created by a POST this replica refuses, so no job id can exist - CircleCI's own 404 for an object that was never created is the whole answer", mode_reviewed: "2026-09-05", tag: "Usage" }
      - { method: "GET", path: "/otel/exporters", area: "otel", tier: 3, status: "green", mode: "derive", mode_reason: "hello-15's TelemetryExporter. The 2026-09-05 reason was that `exporter.endpoint` is a HOSTNAME and `the org's own hosts are a THEME construction a renderer may not replicate (invariant #6)` - so the endpoint is BAKED BY THE THEME AT COMPILE TIME into `telemetry_exporter.endpoint` and read straight off the row here, never composed in the renderer. `headers` publishes the configured header NAMES with CircleCI's own masked value, the same posture the context environment-variable row takes; `issues` is an honest empty, because an exporter this universe never failed to deliver through has none. `org-id` is declared REQUIRED, so a request without it is not a request this operation accepts", mode_reviewed: "2026-09-07", tag: "OTel" }
      - { method: "GET", path: "/owner/{ownerID}/context/{context}/decision", area: "policy", tier: 3, status: "green", mode: "derive", mode_reason: "hello-15's PolicyDecision. The 2026-09-05 reason was that `a decision log entry records a pipeline being EVALUATED against a policy, and this universe has published no policy for anything to be evaluated against` - the canon now publishes the bundle AND logs 107 decisions against it, and A VIOLATION IS EVALUATED RATHER THAN DRAWN: the generator checks each enabled policy's rule against the config document the run was compiled from, so a reader who fetches the bundle, reads the Rego and re-evaluates it against the served config gets the served decision back. NO DECISION IS A HARD_FAIL and that is a fact rather than a gap - a hard fail blocks the pipeline and every pipeline here ran (DECISIONS 2026-09-06 judgment 6), asserted in both suites so a later wave does not read it as an oversight", mode_reviewed: "2026-09-07", tag: "Policy Management" }
      - { method: "GET", path: "/owner/{ownerID}/context/{context}/decision/{decisionID}", area: "policy", tier: 3, status: "green", mode: "derive", mode_reason: "founder re-ruling 2026-09-07: one decision-log entry by id. `metadata` is resolved through the run the decision was made for - build number, project id and the branch the pipeline built - and is OMITTED rather than half-filled when that run is not in this artifact's pipeline model. A decision id that names nothing answers the operation's own `decision log not found`, the sentence this row used to refuse with", mode_reviewed: "2026-09-07", tag: "Policy Management" }
      - { method: "GET", path: "/owner/{ownerID}/context/{context}/decision/{decisionID}/policy-bundle", area: "policy", tier: 3, status: "green", mode: "derive", mode_reason: "founder re-ruling 2026-09-07: the bundle a decision was evaluated AGAINST, which is the policies that were ENABLED when it was made - strictly shorter than the whole bundle `.../policy-bundle` serves, because one policy is written and never enabled. Serving the two identically would make `enabled_rules` and the bundle one fact served twice, which is the thing the canon was shaped to avoid", mode_reviewed: "2026-09-07", tag: "Policy Management" }
      - { method: "GET", path: "/owner/{ownerID}/context/{context}/decision/settings", area: "policy", tier: 3, status: "green", mode: "derive", mode_reason: "hello-15's PolicyDecisionSettings, which carries `enabled` ALONE - one boolean, exactly what DecisionSettings declares. The 2026-09-05 reason named a second field the document does not have", mode_reviewed: "2026-09-07", tag: "Policy Management" }
      - { method: "GET", path: "/owner/{ownerID}/context/{context}/policy-bundle", area: "policy", tier: 3, status: "green", mode: "derive", mode_reason: "hello-15's ConfigPolicy. The 2026-09-05 reason was that `Policy.content` is REGO SOURCE TEXT and `composing a policy document inside a renderer is exactly the invent-at-render-time the judging bar forbids` - so the Rego is composed in the COMPILER from the rule canon carries and the words the theme supplies, the same split the .circleci YAML lives under, and `config_policy.content_sha512` is the hash of exactly those bytes. A DISABLED POLICY IS STILL IN THE BUNDLE, which is what makes a decision's `enabled_rules` strictly shorter than this map rather than the same fact served twice", mode_reviewed: "2026-09-07", tag: "Policy Management" }
      - { method: "GET", path: "/owner/{ownerID}/context/{context}/policy-bundle/{policyName}", area: "policy", tier: 3, status: "green", mode: "derive", mode_reason: "founder re-ruling 2026-09-07: one policy by the name the bundle keys it under - the reader's `configPolicyByName` accessor exists for exactly this addressing. A name that resolves to nothing answers the operation's own inline 404 example, `policy not found`, in envelope 2; the sentence moved from refusals.ts to http.ts's NOT_FOUND unchanged, so a caller sees the same words it always did", mode_reviewed: "2026-09-07", tag: "Policy Management" }
      - { method: "GET", path: "/pipeline", area: "pipelines", tier: 1, status: "green", mode: "derive", tag: "Pipeline" }
      - { method: "GET", path: "/pipeline/{pipeline_id}/values", area: "pipelines", tier: 1, status: "green", mode: "derive", mode_reason: "CircleCI distinguishes pipeline PARAMETERS (declared in a config, which this universe indeed has none of) from pipeline VALUES, which are BUILT IN and which the operation's own description links the pipeline-values reference page for. Every value is a fact about the commit the pipeline built and the canon has carried all of them since hello-2: id, number, project git_url and type, branch, revision, first-parent base_revision, trigger source. `pipeline.git.tag` and the `pipeline.schedule.*` pair are ABSENT rather than empty, because nothing here is tagged or scheduled. So B2.1's proposed empty was a misreading rather than a hard call, and the founder's 2026-09-05 ruling lands on a row that plainly derives. The path key spells the parameter `{pipeline_id}` where the sibling config row spells it `{pipeline-id}` - CircleCI's own inconsistency, left exactly as the document writes it", mode_reviewed: "2026-09-05", tag: "Pipeline" }
      - { method: "GET", path: "/pipeline/{pipeline-id}", area: "pipelines", tier: 1, status: "green", mode: "derive", tag: "Pipeline" }
      - { method: "GET", path: "/pipeline/{pipeline-id}/config", area: "pipelines", tier: 1, status: "green", mode: "derive", mode_reason: "hello-15's CiConfigDocument. The 2026-09-05 reason was that `building one at render time is exactly what generate INTO CANON forbids` - so the document is built in the COMPILER and `ci_config_document.source` is BYTE-IDENTICAL to the blob the file model wrote into the tree (one function produces both), which means this row and a `contents/` fetch of `.circleci/{key}.yml` on the gh host cannot disagree. `compiled` really differs from `source`: it is that source after orb expansion, produced from the same orb document. `setup-config` and `compiled-setup-config` are OMITTED and that omission agrees with an already-served row by construction - `ci_project_settings.setup_workflows` is false and `/project/{provider}/{organization}/{project}/settings` prints that same false", mode_reviewed: "2026-09-07", tag: "Pipeline" }
      - { method: "GET", path: "/pipeline/{pipeline-id}/workflow", area: "pipelines", tier: 1, status: "green", mode: "derive", tag: "Pipeline" }
      - { method: "GET", path: "/project/{project-slug}", area: "projects", tier: 1, status: "green", mode: "derive", tag: "Project" }
      - { method: "GET", path: "/project/{project-slug}/checkout-key", area: "projects", tier: 1, status: "green", mode: "derive", mode_reason: "hello-15's CheckoutKey, and the public half is REAL rather than drawn: canon carries 32 PRNG bytes, the compiler encodes a genuine OpenSSH ssh-ed25519 wire blob and derives BOTH fingerprints from it, so `ssh-keygen -lf` on the served line reproduces the served fingerprint. There is no private half anywhere - a deploy key's public component is published by design and authenticates nothing on its own", mode_reviewed: "2026-09-07", tag: "Project" }
      - { method: "GET", path: "/project/{project-slug}/checkout-key/{fingerprint}", area: "projects", tier: 1, status: "green", mode: "derive", mode_reason: "the same key addressed by either fingerprint. CircleCI reaches one key through this ONE path parameter by md5 OR sha256, so the reader resolves both through a single accessor - splitting them would let the two addressings drift", mode_reviewed: "2026-09-07", tag: "Project" }
      - { method: "GET", path: "/project/{project-slug}/envvar", area: "projects", tier: 1, status: "green", mode: "derive", mode_reason: "one variable per environment this project really deploys to - the project-scoped half of the split CircleCI itself documents (a CONTEXT holds what several projects share; a PROJECT variable holds what is true of this project alone). THE VALUE IS MASKED BY THE OPERATION'S OWN PUBLISHED RULE, four `x` characters plus the last four characters of the value, and no secret exists anywhere in this universe to be masked: the visible tail is DERIVED from the canonical ids, the PagerDuty routing-key precedent (DECISIONS 2026-09-03). `created-at` reproduces the Clojure reader literal the document's own example shows rather than tidying it to RFC-3339 (founder ruling 2026-09-05)", mode_reviewed: "2026-09-05", tag: "Project" }
      - { method: "GET", path: "/project/{project-slug}/envvar/{name}", area: "projects", tier: 1, status: "green", mode: "derive", mode_reason: "the same derivation addressed by name, asserted byte-identical to the row the list prints so a client cannot see two different values for one variable (founder ruling 2026-09-05)", mode_reviewed: "2026-09-05", tag: "Project" }
      - { method: "GET", path: "/project/{project-slug}/pipeline", area: "pipelines", tier: 1, status: "green", mode: "derive", tag: "Pipeline" }
      - { method: "GET", path: "/project/{project-slug}/pipeline/{pipeline-number}", area: "pipelines", tier: 1, status: "green", mode: "derive", tag: "Pipeline" }
      - { method: "GET", path: "/project/{project-slug}/pipeline/mine", area: "pipelines", tier: 1, status: "green", mode: "derive", tag: "Pipeline" }
      - { method: "GET", path: "/project/{project-slug}/schedule", area: "schedules", tier: 2, status: "green", mode: "derive", mode_reason: "hello-15's WorkflowSchedule. The 2026-09-05 reason was exact and it is the reason this row can be served now: `a schedule served here would promise a nightly pipeline that GET /pipeline does not contain, and the first caller to check the two against each other would find it out`. So the canon did not add a schedule ROW, it added ~87 scheduled WorkflowRuns with their own jobs, logs, uploads and outcomes - a schedule is not a row, it is the runs it produced. The pipelines are there to be checked against, and `pinned-cross-category`/`ci-parity` do check. Name and description are canon prose the theme baked at compile time, so the second half of the old reason (`prose canon does not carry`) is answered too", mode_reviewed: "2026-09-07", tag: "Schedule" }
      - { method: "GET", path: "/project/{provider}/{organization}/{project}/settings", area: "projects", tier: 1, status: "green", mode: "derive", mode_reason: "hello-15's CiProjectSettings. Eight of the ten are DERIVED from facts canon already carried (visibility, whether commit statuses exist, whether a push off the default branch really started a run) and two are preferences that say so rather than pretending to a derivation - inventing one for a preference is worse than admitting it is one (DECISIONS 2026-09-06 judgment 7)", mode_reviewed: "2026-09-07", tag: "Project" }
      - { method: "GET", path: "/projects/{project_id}/pipeline-definitions", area: "pipeline-definitions", tier: 2, status: "green", mode: "derive", mode_reason: "one definition per canonical `Workflow` that really ran - ci, lint, release, the same theme-free keys renderer-github serves as the workflow identity on the same runs, in the artifact since hello-2. `description` is ABSENT because every property of `pipelineDefinition` is optional and canon states no prose about a workflow; `repo.external_id` is absent because it is the VCS's own repository id and this host mints none, so emitting one would hand back a value that resolves nowhere (invariant #5). `config_source.file_path` is .circleci/{key}.yml: the directory and extension are CircleCI's own grammar and the only variable part is the canonical key - the canonical `Workflow.path` is NOT reused, because it is a GitHub Actions path and printing it as the file CircleCI reads would state something false about both hosts (founder ruling 2026-09-05)", mode_reviewed: "2026-09-05", tag: "Pipeline Definition" }
      - { method: "GET", path: "/projects/{project_id}/pipeline-definitions/{pipeline_definition_id}", area: "pipeline-definitions", tier: 2, status: "green", mode: "derive", mode_reason: "the same derivation addressed by id (founder ruling 2026-09-05)", mode_reviewed: "2026-09-05", tag: "Pipeline Definition" }
      - { method: "GET", path: "/projects/{project_id}/pipeline-definitions/{pipeline_definition_id}/triggers", area: "triggers", tier: 2, status: "green", mode: "derive", mode_reason: "one trigger per DISTINCT event the canon records that workflow's runs really being started by. A trigger is a claim that pipelines get created when something happens, so a pull-request trigger on a workflow only ever run by pushes would promise pipelines GET /pipeline cannot show - the trigger list is therefore derived from `WorkflowRun.event` rather than from CircleCI's enum. `event_preset` maps the canon's two events onto the two presets the document says every provider supports (all-pushes, only-build-prs); `disabled` is read off `Workflow.state` (founder ruling 2026-09-05)", mode_reviewed: "2026-09-05", tag: "Trigger" }
      - { method: "GET", path: "/projects/{project_id}/triggers/{trigger_id}", area: "triggers", tier: 2, status: "green", mode: "derive", mode_reason: "the same trigger reached directly rather than through its definition, asserted byte-identical to the row the definition's list prints (founder ruling 2026-09-05)", mode_reviewed: "2026-09-05", tag: "Trigger" }
      - { method: "GET", path: "/schedule/{schedule-id}", area: "schedules", tier: 2, status: "green", mode: "derive", mode_reason: "the same derivation addressed by id. A well-formed uuid naming no schedule answers the shared entity 404; an id that is not a uuid answers the operations' own 400, the same split the context family already makes on this host", mode_reviewed: "2026-09-07", tag: "Schedule" }
      - { method: "GET", path: "/user/{id}", area: "users", tier: 1, status: "green", mode: "derive", tag: "User" }
      - { method: "GET", path: "/webhook", area: "webhooks", tier: 2, status: "green", mode: "derive", mode_reason: "the project's outbound build webhook, delivering to the org's own release-bot receiver - canon's `ReceiverSlot` is a CLOSED canonical union whose words are canon's, and the URL is READ OUT OF THE ARTIFACT where the theme baked it at compile time rather than composed in the renderer. `url` is REQUIRED and is a URL, so this is the same bind PagerDuty's `delivery_method.url` was in, resolved with the same canon. `signing_secret` is the document's own masked form ******** on a field described as a MASKED value - mirroring a provider's redaction is not a placeholder, and there is no secret in this universe to redact. `scope-id` and `scope-type` are both declared required and are enforced (founder ruling 2026-09-05)", mode_reviewed: "2026-09-05", tag: "Webhook" }
      - { method: "GET", path: "/webhook/{webhook_id}", area: "webhooks", tier: 2, status: "green", mode: "derive", mode_reason: "the same derivation addressed by id, with its scope asserted to be the project's own id on this host (founder ruling 2026-09-05)", mode_reviewed: "2026-09-05", tag: "Webhook" }
      - { method: "GET", path: "/workflow/{id}", area: "workflows", tier: 1, status: "green", mode: "derive", tag: "Workflow" }
      - { method: "GET", path: "/workflow/{id}/job", area: "workflows", tier: 1, status: "green", mode: "derive", tag: "Workflow" }
    graphql: [] # no GraphQL API exists for this provider (REST-only)
  zendesk:
    rest:
      - { method: "GET", path: "/api/v2/{target_type}/{target_id}/relationship_fields/{field_id}/{source_type}", area: "custom-objects", tier: 3, status: "deferred", mode: "refuse", mode_reason: "lookup relationships point at custom object types, and none is defined, so no lookup relationship field id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Lookup Relationships" }
      - { method: "GET", path: "/api/v2/account/email_settings", area: "account", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06: the `/security_settings` precedent one family over and an order of magnitude smaller — every real account has these and nobody in this universe opened the web UI to change one, with the (A)/(B) provenance stated per field. `custom_dkim_domain: false` follows from there being no custom domain and `send_gmail_messages_via_gmail: false` from `/security_settings` answering `google_login: false`; both links are asserted. The two mail TEMPLATES carry Zendesk's own minimal `{{content}}` rather than the document's two-kilobyte example markup, which would have been this renderer serving somebody else's HTML as this account's", mode_reviewed: "2026-09-06", tag: "Account Settings" }
      - { method: "GET", path: "/api/v2/account/settings", area: "account", tier: 2, status: "deferred", mode: "generate", mode_reason: "NOT CANON-BLOCKED, and this is a scope statement rather than a gap: `AccountSettingsObject` is a thirty-sub-object settings tree and every leaf needs the (A)/(B) provenance pass `/security_settings` and `/account/email_settings` were given in this PR and the last. The two smaller rows were served first deliberately; this one is the next wave's, and it is FLAGGED because `generate` is the closest mode the vocabulary has for 'not built yet' when the blocker is not canon", mode_reviewed: "2026-09-06", held: "provenance-pass", held_reviewed: "2026-09-06", tag: "Account Settings" }
      - { method: "GET", path: "/api/v2/accounts/available", area: "account", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06: this account's own subdomain is taken and every other name is reported available, which is the only half of the answer this universe has. The one operation in the family with no `#### Allowed For` block — the document says outright that credentials are not required, which is also this host's standing posture. Its 200 schema is INLINE, so the conformance entry addresses it by JSON pointer", mode_reviewed: "2026-09-06", tag: "Reseller" }
      - { method: "GET", path: "/api/v2/activities", area: "activity", tier: 2, status: "green", mode: "derive", mode_reason: "CrmActivity — reader.listCrmActivities() / activitiesForCompany(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): CrmActivity in Zendesk's activity envelope, with the verb written in Zendesk's own dotted grammar naming what canon recorded (`crm.call`, `crm.email`, ...) rather than borrowed from the ticket vocabulary, where it would describe something that did not happen", mode_reviewed: "2026-09-04", tag: "Activity Stream" }
      - { method: "GET", path: "/api/v2/activities/{activity_id}", area: "activity", tier: 2, status: "green", mode: "derive", mode_reason: "CrmActivity — reader.listCrmActivities() / activitiesForCompany(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): one CrmActivity, verb as above", mode_reviewed: "2026-09-04", tag: "Activity Stream" }
      - { method: "GET", path: "/api/v2/activities/count", area: "activity", tier: 2, status: "green", mode: "derive", mode_reason: "CrmActivity — reader.listCrmActivities() / activitiesForCompany(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): the count of CrmActivity rows", mode_reviewed: "2026-09-04", tag: "Activity Stream" }
      - { method: "GET", path: "/api/v2/api_tokens", area: "oauth", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the operation's OWN 404 - 'Returned when API token access has been disabled for the account. No response body is returned in this case.' - and API token access was never enabled here. Its sibling 403 is NOT the one armed: GET /api/v2/users/me answers this account's owner with role admin, so a not-an-admin refusal would contradict a served answer. RETIREMENT SCREEN: deprecated: true AND a published removal date, April 30 2027, which has NOT passed - so this refusal is the pre-removal answer and a gateway Retirement entry becomes correct on that date", mode_reviewed: "2026-09-05", tag: "API Tokens" }
      - { method: "GET", path: "/api/v2/approval_requests", area: "task-lists", tier: 3, status: "green", mode: "empty", mode_reason: "approvals are an Agent Workspace flow nobody in this universe started; Zendesk's own answer for an account with none is `{\"approval_requests\": [], \"links\": {\"next\": null, \"prev\": null}, \"meta\": {\"has_more\": false, \"after_cursor\": null, \"before_cursor\": null}}` at 200 — this operation declares ONLY the cursor envelope, and both halves of each go null at the end of a collection, which for an empty one is every page. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Approval Requests" }
      - { method: "GET", path: "/api/v2/attachments/{attachment_id}", area: "attachments", tier: 2, status: "green", mode: "derive", mode_reason: "RE-RULED 2026-09-07, because the 2026-09-06 ruling stopped being true: it served an ENTITY MISS for every id on the ground that \"nothing in this universe has ever attached a file\", and hello-15 attached 45 — every one of them to a ticket comment, uploaded by an agent or a requester. The row now reads `listAttachments()` and serves the file, and answers the same 404 on every older artifact by READING an empty table rather than by asserting emptiness. Still outside both generation gates, for the reason it always was. `content_url` is OMITTED: Zendesk serves attachment bytes from `/attachments/token/…`, which is not under `/api/v2` and carries no row in the pinned document, so there is no covered download for this host to link to — the macro-attachment row, which does have one, publishes it", mode_reviewed: "2026-09-07", tag: "Attachments" }
      - { method: "GET", path: "/api/v2/audit_logs", area: "audit-logs", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: `listAuditEvents()` (gated on `hasAdminAudit()`, its own canon flag). Every actor is a user `/api/v2/users` lists, every `source_id` names a rule this host serves, and every published address is in RFC 5737 documentation space or RFC 1918 private space so it can route to nobody. The six `filter[…]` parameters the document declares are applied against the SHAPED values, so filtering by `source_type=rule` filters on what this host actually serves", mode_reviewed: "2026-09-07", tag: "Audit Logs" }
      - { method: "GET", path: "/api/v2/audit_logs/{audit_log_id}", area: "audit-logs", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: `auditEvent()` — byte-identical to the row the list serves", mode_reviewed: "2026-09-07", tag: "Audit Logs" }
      - { method: "GET", path: "/api/v2/autocomplete/tags", area: "tags", tier: 2, status: "green", mode: "derive", mode_reason: "SupportTicket.tags (the TicketTag enum) — the tag set derives from the tagged rows. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Tags" }
      - { method: "POST", path: "/api/v2/autocomplete/tags", area: "tags", tier: 2, status: "green", mode: "derive", mode_reason: "SupportTicket.tags (the TicketTag enum) — the tag set derives from the tagged rows. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Tags" }
      - { method: "GET", path: "/api/v2/automations", area: "business-rules", tier: 2, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-07: `listSupportAutomations()` + `conditionsFor()` + `actionsFor()`. Every one is asserted to carry at least one TIME condition, which is what makes an automation an automation. DOCUMENT SELF-CONTRADICTION, declared: `AutomationObject.actions[].value` is typed `string` while the same document's `TriggerActionObject` types the same field `oneOf[string,integer,array]`, and Zendesk's notification actions really do carry the recipient/subject/body array. The response is right and the document is wrong, so the rows whose response actually contains such an action sync to `deviation` rather than to green — which is two of these four today, and would be all four if a fifth automation started notifying", mode_reviewed: "2026-09-07", tag: "Automations" }
      - { method: "GET", path: "/api/v2/automations/{automation_id}", area: "business-rules", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: `listSupportAutomations()` + `conditionsFor()` + `actionsFor()`. Every one is asserted to carry at least one TIME condition, which is what makes an automation an automation. DOCUMENT SELF-CONTRADICTION, declared: `AutomationObject.actions[].value` is typed `string` while the same document's `TriggerActionObject` types the same field `oneOf[string,integer,array]`, and Zendesk's notification actions really do carry the recipient/subject/body array. The response is right and the document is wrong, so the rows whose response actually contains such an action sync to `deviation` rather than to green — which is two of these four today, and would be all four if a fifth automation started notifying", mode_reviewed: "2026-09-07", tag: "Automations" }
      - { method: "GET", path: "/api/v2/automations/active", area: "business-rules", tier: 2, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-07: `listSupportAutomations()` + `conditionsFor()` + `actionsFor()`. Every one is asserted to carry at least one TIME condition, which is what makes an automation an automation. DOCUMENT SELF-CONTRADICTION, declared: `AutomationObject.actions[].value` is typed `string` while the same document's `TriggerActionObject` types the same field `oneOf[string,integer,array]`, and Zendesk's notification actions really do carry the recipient/subject/body array. The response is right and the document is wrong, so the rows whose response actually contains such an action sync to `deviation` rather than to green — which is two of these four today, and would be all four if a fifth automation started notifying", mode_reviewed: "2026-09-07", tag: "Automations" }
      - { method: "GET", path: "/api/v2/automations/search", area: "business-rules", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: `listSupportAutomations()` + `conditionsFor()` + `actionsFor()`. Every one is asserted to carry at least one TIME condition, which is what makes an automation an automation. DOCUMENT SELF-CONTRADICTION, declared: `AutomationObject.actions[].value` is typed `string` while the same document's `TriggerActionObject` types the same field `oneOf[string,integer,array]`, and Zendesk's notification actions really do carry the recipient/subject/body array. The response is right and the document is wrong, so the rows whose response actually contains such an action sync to `deviation` rather than to green — which is two of these four today, and would be all four if a fifth automation started notifying", mode_reviewed: "2026-09-07", tag: "Automations" }
      - { method: "GET", path: "/api/v2/bookmarks", area: "bookmarks", tier: 3, status: "green", mode: "empty", mode_reason: "bookmarks are per-agent and nobody in this universe bookmarked a ticket; Zendesk's own answer for an account with none is `{\"bookmarks\": [], \"count\": 0, \"next_page\": null, \"previous_page\": null}` at 200, and the cursor envelope when the caller asks for that dialect. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Bookmarks" }
      - { method: "GET", path: "/api/v2/brand_agents", area: "brands", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06: one membership per agent. `BrandAgentObject.id` is typed STRING by the document and is a decimal numeral in every published example, so the id is minted in the ordinary integer space and stringified at the edge. `url` is omitted because both published examples leave it off every row", mode_reviewed: "2026-09-06", tag: "Brand Agents" }
      - { method: "GET", path: "/api/v2/brand_agents/{brand_agent_id}", area: "brands", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06: one membership by its string id", mode_reviewed: "2026-09-06", tag: "Brand Agents" }
      - { method: "GET", path: "/api/v2/brands", area: "brands", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06, AMENDED 2026-09-07: the account's ONE brand, derived from the artifact's `org` row — `subdomain` IS `org.login` (the same string GitHub serves as the org login) and `brand_url` is that login in Zendesk's own `https://<subdomain>.zendesk.com` grammar. `has_help_center`/`help_center_state` were hard `false`/`disabled` on the ground that this universe modelled no Help Center; hello-15 gave it EIGHT articles across four sections, which `/api/v2/ticket_content_pins` pins to twenty tickets, so the pair now READS `hasSupportDesk()` and answers the old way on every older generation. The manifest still serves no `/help_center/*` row on this provider — Zendesk publishes that API separately and the pinned document carries none of it — which is a coverage fact rather than a reason to deny the help centre exists. `logo` and `host_mapping` are OMITTED rather than emitted empty", mode_reviewed: "2026-09-07", tag: "Brands" }
      - { method: "GET", path: "/api/v2/brands/{brand_id}", area: "brands", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06: the one brand, whose `ticket_form_ids` names the form `/api/v2/ticket_forms` serves", mode_reviewed: "2026-09-06", tag: "Brands" }
      - { method: "GET", path: "/api/v2/brands/{brand_id}/agents", area: "brands", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06: every agent on the roster is a member of the one brand", mode_reviewed: "2026-09-06", tag: "Brand Agents" }
      - { method: "GET", path: "/api/v2/brands/{brand_id}/check_host_mapping", area: "brands", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06: as above, for the one brand; an unknown brand id is the entity 404", mode_reviewed: "2026-09-06", tag: "Brands" }
      - { method: "GET", path: "/api/v2/brands/check_host_mapping", area: "brands", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06: always `is_valid: false` with `reason: not_a_cname` and the account's own `<subdomain>.zendesk.com` as the expected CNAME. This account has configured no custom domain — the brand carries no `host_mapping` for the same reason — so no hostname is currently mapped to it and the answer is true of every argument. `cname` is OMITTED because it is a DNS lookup result this replica does not perform, which the document's own invalid-CNAME example also omits. A judged call, recorded in the review doc", mode_reviewed: "2026-09-06", tag: "Brands" }
      - { method: "GET", path: "/api/v2/channels/twitter/monitored_twitter_handles", area: "channels", tier: 3, status: "green", mode: "empty", mode_reason: "the X (Twitter) channel is not connected to this account; Zendesk's own answer for an account with none is `{\"monitored_twitter_handles\": []}` at 200, with no pagination envelope because the operation declares no paging parameters. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "X Channel" }
      - { method: "GET", path: "/api/v2/channels/twitter/monitored_twitter_handles/{monitored_twitter_handle_id}", area: "channels", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the X (Twitter) channel is not connected to this account, so no monitored handle id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/channels/twitter/monitored_twitter_handles` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "X Channel" }
      - { method: "GET", path: "/api/v2/channels/twitter/tickets/{comment_id}/statuses", area: "channels", tier: 3, status: "green", mode: "empty", mode_reason: "the X (Twitter) channel is not connected to this account; Zendesk's own answer for an account with none is `{\"statuses\": []}` at 200, with no pagination envelope because the operation declares no paging parameters. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "X Channel" }
      - { method: "GET", path: "/api/v2/countries.json", area: "locales", tier: 2, status: "deferred", mode: "generate", mode_reason: "NOT CANON-BLOCKED, and this is a scope statement rather than a gap: Zendesk's country catalog is VENDOR reference data (calling codes and ISO codes for ~250 countries), the same class as the locale catalog this host already serves. It is not derivable from this universe and no licensed copy exists in the tree — the pinned document publishes two example rows and no more. It needs a capture, not a canon entity", mode_reviewed: "2026-09-06", held: "data-licensing", held_reviewed: "2026-09-06", tag: "Countries" }
      - { method: "GET", path: "/api/v2/countries/{id}.json", area: "locales", tier: 2, status: "deferred", mode: "generate", mode_reason: "NOT CANON-BLOCKED, and this is a scope statement rather than a gap: Zendesk's country catalog is VENDOR reference data (calling codes and ISO codes for ~250 countries), the same class as the locale catalog this host already serves. It is not derivable from this universe and no licensed copy exists in the tree — the pinned document publishes two example rows and no more. It needs a capture, not a canon entity", mode_reviewed: "2026-09-06", held: "data-licensing", held_reviewed: "2026-09-06", tag: "Countries" }
      - { method: "GET", path: "/api/v2/custom_objects", area: "custom-objects", tier: 3, status: "green", mode: "empty", mode_reason: "no custom object type was ever defined on this account; Zendesk's own answer for an account with none is `{\"custom_objects\": []}` at 200, with no pagination envelope because the operation declares no paging parameters. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Custom Objects" }
      - { method: "GET", path: "/api/v2/custom_objects/{custom_object_key}", area: "custom-objects", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no custom object type was ever defined on this account, so no object key resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Custom Objects" }
      - { method: "GET", path: "/api/v2/custom_objects/{custom_object_key}/access_rules", area: "custom-objects", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no custom object type exists, so there is no permission set for one, so no object key resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Custom Object Permissions" }
      - { method: "GET", path: "/api/v2/custom_objects/{custom_object_key}/access_rules/{id}", area: "custom-objects", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no custom object type exists, so there is no permission set for one, so no object key resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Custom Object Permissions" }
      - { method: "GET", path: "/api/v2/custom_objects/{custom_object_key}/access_rules/definitions", area: "custom-objects", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no custom object type exists, so there is no permission set for one, so no object key resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Custom Object Permissions" }
      - { method: "GET", path: "/api/v2/custom_objects/{custom_object_key}/fields", area: "custom-objects", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no custom object type exists, so it has no fields, so no object key resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Custom Object Fields" }
      - { method: "GET", path: "/api/v2/custom_objects/{custom_object_key}/fields/{custom_object_field_key_or_id}", area: "custom-objects", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no custom object type exists, so it has no fields, so no object key resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Custom Object Fields" }
      - { method: "GET", path: "/api/v2/custom_objects/{custom_object_key}/limits/field_limit", area: "custom-objects", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no custom object type exists, so it has no fields, so no object key resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Custom Object Fields" }
      - { method: "GET", path: "/api/v2/custom_objects/{custom_object_key}/permission_policies", area: "custom-objects", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no custom object type exists, so there is no permission set for one, so no object key resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Custom Object Permissions" }
      - { method: "GET", path: "/api/v2/custom_objects/{custom_object_key}/permission_policies/{id}", area: "custom-objects", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no custom object type exists, so there is no permission set for one, so no object key resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Custom Object Permissions" }
      - { method: "GET", path: "/api/v2/custom_objects/{custom_object_key}/records", area: "custom-objects", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no custom object type exists, so no record can, so no object key resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Custom Object Records" }
      - { method: "GET", path: "/api/v2/custom_objects/{custom_object_key}/records/{custom_object_record_id}", area: "custom-objects", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no custom object type exists, so no record can, so no record id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Custom Object Records" }
      - { method: "GET", path: "/api/v2/custom_objects/{custom_object_key}/records/{record_id}/attachments", area: "custom-objects", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no custom object record exists to attach anything to, so no record id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Custom Object Record Attachments" }
      - { method: "GET", path: "/api/v2/custom_objects/{custom_object_key}/records/{record_id}/attachments/{id}/download", area: "custom-objects", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no custom object record exists to attach anything to, so no record id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Custom Object Record Attachments" }
      - { method: "GET", path: "/api/v2/custom_objects/{custom_object_key}/records/autocomplete", area: "custom-objects", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no custom object type exists, so no record can, so no object key resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Custom Object Records" }
      - { method: "GET", path: "/api/v2/custom_objects/{custom_object_key}/records/count", area: "custom-objects", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no custom object type exists, so no record can, so no object key resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Custom Object Records" }
      - { method: "GET", path: "/api/v2/custom_objects/{custom_object_key}/records/search", area: "custom-objects", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no custom object type exists, so no record can, so no object key resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Custom Object Records" }
      - { method: "POST", path: "/api/v2/custom_objects/{custom_object_key}/records/search", area: "custom-objects", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no custom object type exists, so no record can, so no object key resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Custom Object Records" }
      - { method: "GET", path: "/api/v2/custom_objects/{custom_object_key}/triggers", area: "business-rules", tier: 2, status: "deferred", mode: "generate", mode_reason: "CANON-BLOCKED (re-scoped 2026-09-07): `SupportTrigger` SHIPPED with hello-15 and this row is now blocked on ONE gap rather than two — the custom-object entity itself, which the whole `/custom_objects` family on this provider is still unclassified for. When a custom object exists, this row is the `/triggers` implementation over it", mode_reviewed: "2026-09-07", tag: "Object Triggers" }
      - { method: "GET", path: "/api/v2/custom_objects/{custom_object_key}/triggers/{trigger_id}", area: "business-rules", tier: 2, status: "deferred", mode: "generate", mode_reason: "CANON-BLOCKED (re-scoped 2026-09-07): `SupportTrigger` SHIPPED with hello-15 and this row is now blocked on ONE gap rather than two — the custom-object entity itself, which the whole `/custom_objects` family on this provider is still unclassified for. When a custom object exists, this row is the `/triggers` implementation over it", mode_reviewed: "2026-09-07", tag: "Object Triggers" }
      - { method: "GET", path: "/api/v2/custom_objects/{custom_object_key}/triggers/active", area: "business-rules", tier: 2, status: "deferred", mode: "generate", mode_reason: "CANON-BLOCKED (re-scoped 2026-09-07): `SupportTrigger` SHIPPED with hello-15 and this row is now blocked on ONE gap rather than two — the custom-object entity itself, which the whole `/custom_objects` family on this provider is still unclassified for. When a custom object exists, this row is the `/triggers` implementation over it", mode_reviewed: "2026-09-07", tag: "Object Triggers" }
      - { method: "GET", path: "/api/v2/custom_objects/{custom_object_key}/triggers/definitions", area: "business-rules", tier: 2, status: "deferred", mode: "generate", mode_reason: "CANON-BLOCKED (re-scoped 2026-09-07): `SupportTrigger` SHIPPED with hello-15 and this row is now blocked on ONE gap rather than two — the custom-object entity itself, which the whole `/custom_objects` family on this provider is still unclassified for. When a custom object exists, this row is the `/triggers` implementation over it", mode_reviewed: "2026-09-07", tag: "Object Triggers" }
      - { method: "GET", path: "/api/v2/custom_objects/{custom_object_key}/triggers/search", area: "business-rules", tier: 2, status: "deferred", mode: "generate", mode_reason: "CANON-BLOCKED (re-scoped 2026-09-07): `SupportTrigger` SHIPPED with hello-15 and this row is now blocked on ONE gap rather than two — the custom-object entity itself, which the whole `/custom_objects` family on this provider is still unclassified for. When a custom object exists, this row is the `/triggers` implementation over it", mode_reviewed: "2026-09-07", tag: "Object Triggers" }
      - { method: "GET", path: "/api/v2/custom_objects/limits/object_limit", area: "custom-objects", tier: 3, status: "green", mode: "empty", mode_reason: "no custom object type was ever defined on this account; Zendesk's own answer for an account with none is `{\"count\": 0}` at 200. `limit` is OMITTED rather than emitted: the account's plan cap is a number this replica has no source for, and inventing one is the placeholder invariant #4 forbids. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Custom Objects" }
      - { method: "GET", path: "/api/v2/custom_objects/limits/record_limit", area: "custom-objects", tier: 3, status: "green", mode: "empty", mode_reason: "no custom object type exists, so no record can; Zendesk's own answer for an account with none is `{\"count\": 0}` at 200. `limit` is OMITTED rather than emitted: the account's plan cap is a number this replica has no source for, and inventing one is the placeholder invariant #4 forbids. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Custom Object Records" }
      - { method: "GET", path: "/api/v2/custom_roles", area: "roles", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06 as a COMPUTED empty: a custom role exists exactly when some agent holds one, and every agent this host serves carries one of Zendesk's BUILT-IN roles (`roleOfCrmUser` answers `admin` or `agent`) with `shapeAgent` omitting `custom_role_id` entirely. Canon's `CrmUserRole` is a JOB TITLE (`account-executive`, `support-manager`), not a Zendesk permission set. The entry asserts the link to the roster, never the emptiness", mode_reviewed: "2026-09-06", tag: "Custom Roles" }
      - { method: "GET", path: "/api/v2/custom_roles/{custom_role_id}", area: "roles", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06 as an ENTITY MISS: no custom role is defined, so no id resolves", mode_reviewed: "2026-09-06", tag: "Custom Roles" }
      - { method: "GET", path: "/api/v2/custom_statuses", area: "ticket-forms", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06: one custom status per `status_category` this desk actually uses. `CustomStatusObject`'s own enum is `new|open|pending|hold|solved` — canon's `TicketStatus` MINUS `closed`, which Zendesk models as terminal and gives no custom status — and every category served names a status some ticket is really in", mode_reviewed: "2026-09-06", tag: "Custom Ticket Statuses" }
      - { method: "GET", path: "/api/v2/custom_statuses/{custom_status_id}", area: "ticket-forms", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06: one custom status, asserted identical to the row the list serves", mode_reviewed: "2026-09-06", tag: "Custom Ticket Statuses" }
      - { method: "GET", path: "/api/v2/deleted_tickets", area: "tickets", tier: 1, status: "green", mode: "derive", mode_reason: "SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): EMPTY: nothing in this universe was ever deleted, which is a statement about the account rather than about the artifact (the generation gap covers the other case)", mode_reviewed: "2026-09-04", tag: "Tickets" }
      - { method: "GET", path: "/api/v2/deleted_users", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): EMPTY: nothing in this universe was ever deleted", mode_reviewed: "2026-09-04", tag: "Users" }
      - { method: "GET", path: "/api/v2/deleted_users/{deleted_user_id}", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): the ENTITY 404 for every id, which is the correct answer for a record that does not exist and the one row-class in this wave whose conformance check asserts the 404 contract rather than a 200 schema (the document publishes no schema for its 404)", mode_reviewed: "2026-09-04", tag: "Users" }
      - { method: "GET", path: "/api/v2/deleted_users/count", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): 0, agreeing with the empty collection beside it", mode_reviewed: "2026-09-04", tag: "Users" }
      - { method: "GET", path: "/api/v2/deletion_schedules", area: "security", tier: 3, status: "green", mode: "empty", mode_reason: "no scheduled deletion was ever created; Zendesk's own answer for an account with none is `{\"deletion_schedules\": []}` at 200, with no pagination envelope because the operation declares no paging parameters. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Deletion Schedules" }
      - { method: "GET", path: "/api/v2/deletion_schedules/{deletion_schedule_id}", area: "security", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no scheduled deletion was ever created, so no deletion schedule id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/deletion_schedules` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Deletion Schedules" }
      - { method: "GET", path: "/api/v2/dynamic_content/items", area: "dynamic-content", tier: 3, status: "green", mode: "empty", mode_reason: "dynamic content exists to translate canned prose across locales, and this account has one locale enabled; Zendesk's own answer for an account with none is `{\"items\": []}` at 200, with no pagination envelope because the operation declares no paging parameters. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Dynamic Content" }
      - { method: "GET", path: "/api/v2/dynamic_content/items/{dynamic_content_item_id}", area: "dynamic-content", tier: 3, status: "deferred", mode: "refuse", mode_reason: "dynamic content exists to translate canned prose across locales, and this account has one locale enabled, so no dynamic content item id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/dynamic_content/items` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Dynamic Content" }
      - { method: "GET", path: "/api/v2/dynamic_content/items/{dynamic_content_item_id}/variants", area: "dynamic-content", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no dynamic content item exists to have variants of, so no dynamic content item id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/dynamic_content/items` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Dynamic Content Item Variants" }
      - { method: "GET", path: "/api/v2/dynamic_content/items/{dynamic_content_item_id}/variants/{dynamic_content_variant_id}", area: "dynamic-content", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no dynamic content item exists to have variants of, so no dynamic content item id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/dynamic_content/items` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Dynamic Content Item Variants" }
      - { method: "GET", path: "/api/v2/dynamic_content/items/show_many", area: "dynamic-content", tier: 3, status: "green", mode: "empty", mode_reason: "dynamic content exists to translate canned prose across locales, and this account has one locale enabled; Zendesk's own answer for an account with none is `{\"items\": []}` at 200, with no pagination envelope because the operation declares no paging parameters. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Dynamic Content" }
      - { method: "GET", path: "/api/v2/email_notifications", area: "notifications", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: `listEmailNotifications()` + `recipientsFor()`. Each names a comment that is really on the ticket it names, and each recipient's `delivery_status.code` is canon's `DELIVERY_STATUS_CODE` — an SMTP reply plus DSN status, a protocol fact rather than a draw", mode_reviewed: "2026-09-07", tag: "Email Notifications" }
      - { method: "GET", path: "/api/v2/email_notifications/{notification_id}", area: "notifications", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: `emailNotification()`, with the RFC 5322 Message-Id the compiler built", mode_reviewed: "2026-09-07", tag: "Email Notifications" }
      - { method: "GET", path: "/api/v2/email_notifications/show_many", area: "notifications", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: the same accessor filtered by `ids`/`comment_ids`/`ticket_ids`, under the PLURAL key. The document declares `EmailNotificationResponse` (singular) on an operation called \"Show Many\" — the mirror image of `/suspended_tickets/{id}` and resolved the same way (DECISIONS 2026-09-07)", mode_reviewed: "2026-09-07", tag: "Email Notifications" }
      - { method: "GET", path: "/api/v2/end_users/{user_id}/identities", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "Contact — the email identity Zendesk models as a separate record is a field on the canon row. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "User Identities" }
      - { method: "GET", path: "/api/v2/end_users/{user_id}/identities/{user_identity_id}", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "Contact — the email identity Zendesk models as a separate record is a field on the canon row. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "User Identities" }
      - { method: "GET", path: "/api/v2/group_memberships", area: "groups", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser.team — the same join, in Zendesk's membership dialect. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Group Memberships" }
      - { method: "GET", path: "/api/v2/group_memberships/{group_membership_id}", area: "groups", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser.team — the same join, in Zendesk's membership dialect. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Group Memberships" }
      - { method: "GET", path: "/api/v2/group_memberships/assignable", area: "groups", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser.team — the same join, in Zendesk's membership dialect. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Group Memberships" }
      - { method: "GET", path: "/api/v2/group_slas/policies", area: "sla", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06 as a COMPUTED empty: a group SLA sets a group-OWNERSHIP target per group, and `FIRST_RESPONSE_TARGET_SEC` is the only support target in the whole canon — so the count is the number of groups that have one. The entry asserts that the account's SLA policy measures `first_reply_time` and nothing else, which is what makes the emptiness FOLLOW rather than be asserted", mode_reviewed: "2026-09-06", tag: "Group SLA Policies" }
      - { method: "GET", path: "/api/v2/group_slas/policies/{group_sla_policy_id}", area: "sla", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06 as an ENTITY MISS: no group SLA policy exists, so no ULID resolves", mode_reviewed: "2026-09-06", tag: "Group SLA Policies" }
      - { method: "GET", path: "/api/v2/group_slas/policies/definitions", area: "sla", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06: a real derive even though the policy list is empty — it names the groups a policy could be written against, and those are this host's own. NOTE the document types this filter's `values.list[].value` as an INTEGER where the SLA twin types it a string; the two rows differ exactly where the document does, and conformance caught the first attempt to make them agree", mode_reviewed: "2026-09-06", tag: "Group SLA Policies" }
      - { method: "GET", path: "/api/v2/groups", area: "groups", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser.team (the `sales`/`support`/`success` CrmTeam) — Zendesk's agent groups. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Groups" }
      - { method: "GET", path: "/api/v2/groups/{group_id}", area: "groups", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser.team (the `sales`/`support`/`success` CrmTeam) — Zendesk's agent groups. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Groups" }
      - { method: "GET", path: "/api/v2/groups/{group_id}/memberships", area: "groups", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser.team — the same join, in Zendesk's membership dialect. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Group Memberships" }
      - { method: "GET", path: "/api/v2/groups/{group_id}/memberships/assignable", area: "groups", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser.team — the same join, in Zendesk's membership dialect. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Group Memberships" }
      - { method: "GET", path: "/api/v2/groups/{group_id}/users", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Users" }
      - { method: "GET", path: "/api/v2/groups/{group_id}/users/count", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Users" }
      - { method: "GET", path: "/api/v2/groups/assignable", area: "groups", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser.team (the `sales`/`support`/`success` CrmTeam) — Zendesk's agent groups. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Groups" }
      - { method: "GET", path: "/api/v2/groups/autocomplete", area: "groups", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser.team (the `sales`/`support`/`success` CrmTeam) — Zendesk's agent groups. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Groups" }
      - { method: "GET", path: "/api/v2/groups/available_agents", area: "groups", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser.team (the `sales`/`support`/`success` CrmTeam) — Zendesk's agent groups. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Groups" }
      - { method: "GET", path: "/api/v2/groups/count", area: "groups", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser.team (the `sales`/`support`/`success` CrmTeam) — Zendesk's agent groups. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Groups" }
      - { method: "GET", path: "/api/v2/groups/default", area: "groups", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser.team (the `sales`/`support`/`success` CrmTeam) — Zendesk's agent groups. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Groups" }
      - { method: "GET", path: "/api/v2/incremental/{incremental_resource}/sample", area: "incremental-export", tier: 2, status: "green", mode: "derive", mode_reason: "the cursor/start_time dialect over SupportTicket, Contact and Company — all three exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): tickets, users and organizations only — the parameter is not a wildcard, and any other resource is a coverage 404", mode_reviewed: "2026-09-04", tag: "Incremental Export" }
      - { method: "GET", path: "/api/v2/incremental/custom_objects/{custom_object_key}/cursor", area: "custom-objects", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no custom object type exists, so no record can, so no object key resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Custom Object Records" }
      - { method: "GET", path: "/api/v2/incremental/organizations", area: "incremental-export", tier: 2, status: "green", mode: "derive", mode_reason: "the cursor/start_time dialect over SupportTicket, Contact and Company — all three exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Incremental Export" }
      - { method: "GET", path: "/api/v2/incremental/routing/attribute_values", area: "routing", tier: 3, status: "green", mode: "empty", mode_reason: "the incremental export of a routing surface that has no records; Zendesk's own answer for an account with none is `{\"attribute_values\": [], \"count\": 0, \"end_time\": <the universe's own anchor>, \"next_page\": null}` at 200 — the anchor rather than the wall clock, because a pinned host whose incremental cursor moved every day would not be pinned. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Incremental Skill Based Routing" }
      - { method: "GET", path: "/api/v2/incremental/routing/attributes", area: "routing", tier: 3, status: "green", mode: "empty", mode_reason: "the incremental export of a routing surface that has no records; Zendesk's own answer for an account with none is `{\"attributes\": [], \"count\": 0, \"end_time\": <the universe's own anchor>, \"next_page\": null}` at 200 — the anchor rather than the wall clock, because a pinned host whose incremental cursor moved every day would not be pinned. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Incremental Skill Based Routing" }
      - { method: "GET", path: "/api/v2/incremental/routing/instance_values", area: "routing", tier: 3, status: "green", mode: "empty", mode_reason: "the incremental export of a routing surface that has no records; Zendesk's own answer for an account with none is `{\"instance_values\": [], \"count\": 0, \"end_time\": <the universe's own anchor>, \"next_page\": null}` at 200 — the anchor rather than the wall clock, because a pinned host whose incremental cursor moved every day would not be pinned. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Incremental Skill Based Routing" }
      - { method: "GET", path: "/api/v2/incremental/ticket_events", area: "incremental-export", tier: 2, status: "green", mode: "derive", mode_reason: "the cursor/start_time dialect over SupportTicket, Contact and Company — all three exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Incremental Export" }
      - { method: "GET", path: "/api/v2/incremental/ticket_metric_events", area: "ticket-metrics", tier: 2, status: "green", mode: "derive", mode_reason: "TicketFieldChange plus SupportTicket's own timings. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): `reply_time` and `resolution_time` only: the other four Zendesk metrics are pause/resume integrals over a status history canon does not carry at that resolution, and are not fabricated", mode_reviewed: "2026-09-04", tag: "Ticket Metric Events" }
      - { method: "GET", path: "/api/v2/incremental/tickets", area: "incremental-export", tier: 2, status: "green", mode: "derive", mode_reason: "the cursor/start_time dialect over SupportTicket, Contact and Company — all three exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Incremental Export" }
      - { method: "GET", path: "/api/v2/incremental/tickets/cursor", area: "incremental-export", tier: 2, status: "green", mode: "derive", mode_reason: "the cursor/start_time dialect over SupportTicket, Contact and Company — all three exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Incremental Export" }
      - { method: "GET", path: "/api/v2/incremental/users", area: "incremental-export", tier: 2, status: "green", mode: "derive", mode_reason: "the cursor/start_time dialect over SupportTicket, Contact and Company — all three exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Incremental Export" }
      - { method: "GET", path: "/api/v2/incremental/users/cursor", area: "incremental-export", tier: 2, status: "green", mode: "derive", mode_reason: "the cursor/start_time dialect over SupportTicket, Contact and Company — all three exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Incremental Export" }
      - { method: "GET", path: "/api/v2/it_asset_management/asset_types", area: "itam", tier: 3, status: "green", mode: "empty", mode_reason: "IT asset management is not licensed on this account; Zendesk's own answer for an account with none is `{\"asset_types\": []}` at 200, with no pagination envelope because the operation declares no paging parameters. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "ITAM Asset Types" }
      - { method: "GET", path: "/api/v2/it_asset_management/asset_types/{asset_type_id}", area: "itam", tier: 3, status: "deferred", mode: "refuse", mode_reason: "IT asset management is not licensed on this account, so no asset type id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/it_asset_management/asset_types` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "ITAM Asset Types" }
      - { method: "GET", path: "/api/v2/it_asset_management/asset_types/{asset_type_id}/fields", area: "itam", tier: 3, status: "deferred", mode: "refuse", mode_reason: "IT asset management is not licensed on this account, so no asset type id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/it_asset_management/asset_types` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "ITAM Asset Fields" }
      - { method: "GET", path: "/api/v2/it_asset_management/asset_types/{asset_type_id}/fields/{asset_type_field_id}", area: "itam", tier: 3, status: "deferred", mode: "refuse", mode_reason: "IT asset management is not licensed on this account, so no asset type id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/it_asset_management/asset_types` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "ITAM Asset Fields" }
      - { method: "GET", path: "/api/v2/it_asset_management/assets", area: "itam", tier: 3, status: "green", mode: "empty", mode_reason: "IT asset management is a separately-licensed product this account does not carry; Zendesk's own answer for an account with none is `{\"assets\": [], \"links\": {\"next\": null, \"prev\": null}, \"meta\": {\"has_more\": false, \"after_cursor\": null, \"before_cursor\": null}}` at 200 — this operation declares ONLY the cursor envelope, and both halves of each go null at the end of a collection, which for an empty one is every page. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "ITAM Assets" }
      - { method: "GET", path: "/api/v2/it_asset_management/assets/{asset_id}", area: "itam", tier: 3, status: "deferred", mode: "refuse", mode_reason: "IT asset management is a separately-licensed product this account does not carry, so no asset id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/it_asset_management/assets` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "ITAM Assets" }
      - { method: "GET", path: "/api/v2/it_asset_management/assets/search", area: "itam", tier: 3, status: "green", mode: "empty", mode_reason: "IT asset management is a separately-licensed product this account does not carry; Zendesk's own answer for an account with none is `{\"assets\": [], \"links\": {\"next\": null, \"prev\": null}, \"meta\": {\"has_more\": false, \"after_cursor\": null, \"before_cursor\": null}}` at 200 — this operation declares ONLY the cursor envelope, and both halves of each go null at the end of a collection, which for an empty one is every page. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "ITAM Assets" }
      - { method: "POST", path: "/api/v2/it_asset_management/assets/search", area: "itam", tier: 3, status: "green", mode: "empty", mode_reason: "IT asset management is a separately-licensed product this account does not carry; Zendesk's own answer for an account with none is `{\"assets\": [], \"links\": {\"next\": null, \"prev\": null}, \"meta\": {\"has_more\": false, \"after_cursor\": null, \"before_cursor\": null}}` at 200 — this operation declares ONLY the cursor envelope, and both halves of each go null at the end of a collection, which for an empty one is every page. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "ITAM Assets" }
      - { method: "GET", path: "/api/v2/it_asset_management/locations", area: "itam", tier: 3, status: "green", mode: "empty", mode_reason: "IT asset management is not licensed on this account; Zendesk's own answer for an account with none is `{\"locations\": [], \"links\": {\"next\": null, \"prev\": null}, \"meta\": {\"has_more\": false, \"after_cursor\": null, \"before_cursor\": null}}` at 200 — this operation declares ONLY the cursor envelope, and both halves of each go null at the end of a collection, which for an empty one is every page. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "ITAM Asset Locations" }
      - { method: "GET", path: "/api/v2/it_asset_management/locations/{location_id}", area: "itam", tier: 3, status: "deferred", mode: "refuse", mode_reason: "IT asset management is not licensed on this account, so no asset location id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/it_asset_management/locations` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "ITAM Asset Locations" }
      - { method: "GET", path: "/api/v2/it_asset_management/statuses", area: "itam", tier: 3, status: "green", mode: "empty", mode_reason: "IT asset management is not licensed on this account; Zendesk's own answer for an account with none is `{\"statuses\": []}` at 200, with no pagination envelope because the operation declares no paging parameters. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "ITAM Asset Statuses" }
      - { method: "GET", path: "/api/v2/it_asset_management/statuses/{status_id}", area: "itam", tier: 3, status: "deferred", mode: "refuse", mode_reason: "IT asset management is not licensed on this account, so no asset status id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/it_asset_management/statuses` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "ITAM Asset Statuses" }
      - { method: "GET", path: "/api/v2/job_statuses", area: "job-statuses", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: `listBulkJobs()` + `bulkJobItems()`. `total`/`progress` are asserted to count the items rather than to be stored beside them, and every item names a ticket this host serves. The id is the opaque 32-hex string the document's own examples carry, not an integer", mode_reviewed: "2026-09-07", tag: "Job Statuses" }
      - { method: "GET", path: "/api/v2/job_statuses/{job_status_id}", area: "job-statuses", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: `bulkJob()` — byte-identical to the row the list serves", mode_reviewed: "2026-09-07", tag: "Job Statuses" }
      - { method: "GET", path: "/api/v2/job_statuses/show_many", area: "job-statuses", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: the same jobs by `?ids=`, matching on the opaque string rather than on a number", mode_reviewed: "2026-09-07", tag: "Job Statuses" }
      - { method: "GET", path: "/api/v2/locales", area: "locales", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-04", tag: "Locales" }
      - { method: "GET", path: "/api/v2/locales/{locale_id}", area: "locales", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-04", tag: "Locales" }
      - { method: "GET", path: "/api/v2/locales/agent", area: "locales", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-04", tag: "Locales" }
      - { method: "GET", path: "/api/v2/locales/current", area: "locales", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-04", tag: "Locales" }
      - { method: "GET", path: "/api/v2/locales/detect_best_locale", area: "locales", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-04", tag: "Locales" }
      - { method: "GET", path: "/api/v2/locales/public", area: "locales", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-04", tag: "Locales" }
      - { method: "GET", path: "/api/v2/macros", area: "business-rules", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: `listSupportMacros()` + `actionsFor(macro)`, with the four `usage_*` counters COUNTED from `macroUsageSince()` over the applications canon derived off the tickets' own audit trail — so `/macros/most_used` and the counters cannot disagree, and both name tickets this host serves. A canned comment expands into Zendesk's own TWO actions (`comment_value` + `comment_mode_is_public`). `categories` is canon's `category_name` — the folder the two-level title was composed from, not a re-parse of it", mode_reviewed: "2026-09-07", tag: "Macros" }
      - { method: "GET", path: "/api/v2/macros/{macro_id}", area: "business-rules", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: `listSupportMacros()` + `actionsFor(macro)`, with the four `usage_*` counters COUNTED from `macroUsageSince()` over the applications canon derived off the tickets' own audit trail — so `/macros/most_used` and the counters cannot disagree, and both name tickets this host serves. A canned comment expands into Zendesk's own TWO actions (`comment_value` + `comment_mode_is_public`). `categories` is canon's `category_name` — the folder the two-level title was composed from, not a re-parse of it", mode_reviewed: "2026-09-07", tag: "Macros" }
      - { method: "GET", path: "/api/v2/macros/{macro_id}/apply", area: "business-rules", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: `actionsFor(macro)` projected into `MacroApplyTicketResponse` — the changes the macro WOULD make, against no ticket, so the result names none", mode_reviewed: "2026-09-07", tag: "Macros" }
      - { method: "GET", path: "/api/v2/macros/{macro_id}/attachments", area: "business-rules", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: `attachmentsForMacro(macro)`. Two macros carry a file since PR C (#384) — which matters, because a single one made the by-id row unfalsifiable: any id that resolved was the only id there was. A macro with no file is an honest empty list; an unknown macro is the 404", mode_reviewed: "2026-09-07", tag: "Macros" }
      - { method: "GET", path: "/api/v2/macros/actions", area: "business-rules", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: the action grammar COMPUTED from `actionsFor()` over the account's own eleven macros rather than from a hand-written table — conformance asserts the join in BOTH directions, so no macro can use a subject the definitions omit and no definition can advertise one no macro uses", mode_reviewed: "2026-09-07", tag: "Macros" }
      - { method: "GET", path: "/api/v2/macros/active", area: "business-rules", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: `listSupportMacros()` + `actionsFor(macro)`, with the four `usage_*` counters COUNTED from `macroUsageSince()` over the applications canon derived off the tickets' own audit trail — so `/macros/most_used` and the counters cannot disagree, and both name tickets this host serves. A canned comment expands into Zendesk's own TWO actions (`comment_value` + `comment_mode_is_public`). `categories` is canon's `category_name` — the folder the two-level title was composed from, not a re-parse of it", mode_reviewed: "2026-09-07", tag: "Macros" }
      - { method: "GET", path: "/api/v2/macros/attachments/{attachment_id}", area: "business-rules", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: `listAttachments()` filtered to the macro-attached file. `MacroAttachmentObject` is a DIFFERENT object from `AttachmentObject` — six fields, `filename` not `file_name` — and its `content_url` addresses the `/content` row below, which this host really serves", mode_reviewed: "2026-09-07", tag: "Macros" }
      - { method: "GET", path: "/api/v2/macros/attachments/{attachment_id}/content", area: "business-rules", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: the artifact's own BYTES (`AttachmentRow.body`), with the file's content type from canon's `ATTACHMENT_CONTENT_TYPE` and a `content-disposition` naming it. The conformance entry re-hashes what was served and compares it to the sha256 the compiler measured", mode_reviewed: "2026-09-07", tag: "Macros" }
      - { method: "GET", path: "/api/v2/macros/categories", area: "business-rules", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: `macroCategories()` — the DISTINCT `category_name` column, which is what Zendesk's category list is (it has no macro-category object and derives the whole list from the `Category::Title` prefix a macro's title carries). Reading the column rather than re-splitting the title keeps one derivation in the layer that owns it, so this row and the `categories` field on every macro cannot disagree. A PLAIN NON-EMPTY DERIVE: the first cut of this wave computed an empty list and flagged a possible `empty` re-ruling, and PR C (#384) gave every macro a folder, so the flag is withdrawn", mode_reviewed: "2026-09-07", tag: "Macros" }
      - { method: "GET", path: "/api/v2/macros/definitions", area: "business-rules", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: the same grammar as `/macros/actions` under the document's nested spelling; a test binds the two byte for byte", mode_reviewed: "2026-09-07", tag: "Macros" }
      - { method: "GET", path: "/api/v2/macros/groups", area: "business-rules", tier: 2, status: "deferred", mode: "generate", mode_reason: "RE-SCOPED 2026-09-07, and it is no longer canon that blocks it: `SupportMacro` shipped with hello-15 and eleven macros are served. `ListMacrosByGroup` returns macros grouped by AGENT GROUP, and every macro in this account is either unrestricted or restricted to one group — so the grouping this row expresses is derivable. It is left uncovered because the document publishes no schema for the response beyond an untyped object and no example of the grouping key, and guessing the key would be inventing the one thing the row is about. Needs a CAPTURE. It is also this wave's shadowing finding: the literal `groups` sits exactly where `/macros/{macro_id}` puts a parameter, and a served test now asserts it reaches the coverage 404 rather than being reported as a macro that does not exist", mode_reviewed: "2026-09-07", tag: "Macros" }
      - { method: "GET", path: "/api/v2/macros/most_used", area: "business-rules", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: `macroUsageSince(anchor - 30d, anchor)` ranked, projected through `MostUsedMacroObject`'s smaller shape. The window ends at the ARTIFACT'S ANCHOR rather than the wall clock, so a pinned snapshot answers the same ranking forever (invariant #1)", mode_reviewed: "2026-09-07", tag: "Macros" }
      - { method: "GET", path: "/api/v2/macros/new", area: "business-rules", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: `listSupportMacros()` + `actionsFor(macro)`, with the four `usage_*` counters COUNTED from `macroUsageSince()` over the applications canon derived off the tickets' own audit trail — so `/macros/most_used` and the counters cannot disagree, and both name tickets this host serves. A canned comment expands into Zendesk's own TWO actions (`comment_value` + `comment_mode_is_public`). `categories` is canon's `category_name` — the folder the two-level title was composed from, not a re-parse of it", mode_reviewed: "2026-09-07", tag: "Macros" }
      - { method: "GET", path: "/api/v2/macros/search", area: "business-rules", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: `listSupportMacros()` + `actionsFor(macro)`, with the four `usage_*` counters COUNTED from `macroUsageSince()` over the applications canon derived off the tickets' own audit trail — so `/macros/most_used` and the counters cannot disagree, and both name tickets this host serves. A canned comment expands into Zendesk's own TWO actions (`comment_value` + `comment_mode_is_public`). `categories` is canon's `category_name` — the folder the two-level title was composed from, not a re-parse of it", mode_reviewed: "2026-09-07", tag: "Macros" }
      - { method: "GET", path: "/api/v2/oauth/clients", area: "oauth", tier: 3, status: "green", mode: "empty", mode_reason: "a registry nobody populated is an empty collection, not a refusal: no OAuth client was ever registered on this account, and Zendesk answers an admin caller 200 with the empty `clients` array rather than a 403. The refuse wave's proposal (an account-owner 403) was CONTRADICTED by this same host - the operation's pinned `Allowed For` says Admins and GET /api/v2/users/me answers the account owner with role admin (founder ruling 2026-09-06, coverage/reviews/2026-09-06-zendesk-rulings.md)", mode_reviewed: "2026-09-06", tag: "OAuth Clients" }
      - { method: "GET", path: "/api/v2/oauth/clients/{oauth_client_id}", area: "oauth", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no OAuth client was ever registered on this account, so no client id can resolve - the provider's own not-found is the whole answer", mode_reviewed: "2026-09-05", tag: "OAuth Clients" }
      - { method: "GET", path: "/api/v2/oauth/global_clients", area: "oauth", tier: 3, status: "green", mode: "empty", mode_reason: "a registry nobody populated is an empty collection, not a refusal: this account has authorized no global OAuth client, and the LIST answers 200 with the empty `global_clients` array. Same contradiction as /oauth/clients - the proposed 403 would have denied an admin caller this host already serves (founder ruling 2026-09-06, coverage/reviews/2026-09-06-zendesk-rulings.md)", mode_reviewed: "2026-09-06", tag: "Global Clients" }
      - { method: "GET", path: "/api/v2/oauth/global_clients/{global_client_id}", area: "oauth", tier: 3, status: "deferred", mode: "refuse", mode_reason: "this account has authorized no global OAuth client, so no global client id can resolve", mode_reviewed: "2026-09-05", tag: "Global Clients" }
      - { method: "GET", path: "/api/v2/oauth/global_clients/token_summary", area: "oauth", tier: 3, status: "green", mode: "derive", mode_reason: "GlobalClientsTokenSummaryResponse is one {id, last_used_at, tokens_count} summary PER global client, so a summary over the registry served empty beside it is the computed empty array rather than a refusal. SERVED 2026-09-06 (coverage/reviews/2026-09-06-zendesk-rulings.md): `derive` and not `empty` because the value is a FUNCTION of /api/v2/oauth/global_clients - the day a client exists both rows move together and neither needs a re-ruling", mode_reviewed: "2026-09-06", tag: "Global Clients" }
      - { method: "GET", path: "/api/v2/oauth/tokens", area: "oauth", tier: 3, status: "green", mode: "empty", mode_reason: "no OAuth grant was ever made on this account, so the token list is a real collection with nothing in it - this replica authenticates a caller with an API key rather than an OAuth grant. The proposed account-owner 403 was contradicted the same way as the two client registries above (founder ruling 2026-09-06, coverage/reviews/2026-09-06-zendesk-rulings.md)", mode_reviewed: "2026-09-06", tag: "OAuth Tokens" }
      - { method: "GET", path: "/api/v2/oauth/tokens/{oauth_token_id}", area: "oauth", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no OAuth grant was ever made on this account, so no token id can resolve", mode_reviewed: "2026-09-05", tag: "OAuth Tokens" }
      - { method: "GET", path: "/api/v2/oauth/tokens/current", area: "oauth", tier: 3, status: "deferred", mode: "refuse", mode_reason: "this replica authenticates a caller with an API key rather than an OAuth grant, so there is no current OAuth token to describe", mode_reviewed: "2026-09-05", tag: "OAuth Tokens" }
      - { method: "GET", path: "/api/v2/organization_fields", area: "custom-fields", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06, ACCEPTED after being sent back the same day: canon's `Company` attributes (industry, segment, size band, employees, annual revenue, relationship, lifecycle stage, region) as Zendesk custom organization fields. THE SEND-BACK AND THE RULING: the configuration wave built this, then removed it because `parity/crm-crm-parity.test.ts` ruled as DOCUMENTED DIFFERENCE (5) that a Zendesk organization's `organization_fields` bag stays `{}` - asserted as an ABSENCE so it could not be quietly filled - and rewriting a reasoned parity assertion to match new code is the same failure as hand-editing a status to green. The founder accepted the re-proposal: that note's premise was that a client could only HARDCODE the keys and would break on a base-URL swap, which held only while NO CATALOG ENDPOINT existed to discover them from. This row is that endpoint. DOCUMENTED DIFFERENCE (5) is now the STRONGER claim rather than the weaker one - the six facts HubSpot publishes off the same `CompanyRow` columns must be IDENTICAL on both hosts, which makes the parity suite sensitive to a host serving a DIFFERENT industry for one canonical company, a class an absence check could never catch (invariant #5)", mode_reviewed: "2026-09-06", tag: "Organization Fields" }
      - { method: "GET", path: "/api/v2/organization_fields/{organization_field_id}", area: "custom-fields", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06: one definition, by id or by key", mode_reviewed: "2026-09-06", tag: "Organization Fields" }
      - { method: "GET", path: "/api/v2/organization_memberships", area: "organizations", tier: 1, status: "green", mode: "derive", mode_reason: "Contact -> Company — reader.contactsFor(company). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Organization Memberships" }
      - { method: "GET", path: "/api/v2/organization_memberships/{organization_membership_id}", area: "organizations", tier: 1, status: "green", mode: "derive", mode_reason: "Contact -> Company — reader.contactsFor(company). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Organization Memberships" }
      - { method: "GET", path: "/api/v2/organization_merges/{organization_merge_id}", area: "organizations", tier: 1, status: "green", mode: "derive", mode_reason: "Company — reader.listCompanies() / companyByDomain(); Zendesk organizations ARE the customer companies. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): the ENTITY 404 for every id: nothing in this universe was ever merged, and the document publishes no schema for this operation's 404, so conformance asserts the captured RecordNotFound contract instead", mode_reviewed: "2026-09-04", tag: "Organizations" }
      - { method: "GET", path: "/api/v2/organization_subscriptions", area: "organizations", tier: 3, status: "green", mode: "derive", mode_reason: "Contact -> Company, the same join Zendesk exposes as a subscription. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Organization Subscriptions" }
      - { method: "GET", path: "/api/v2/organization_subscriptions/{organization_subscription_id}", area: "organizations", tier: 3, status: "green", mode: "derive", mode_reason: "Contact -> Company, the same join Zendesk exposes as a subscription. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Organization Subscriptions" }
      - { method: "GET", path: "/api/v2/organizations", area: "organizations", tier: 1, status: "green", mode: "derive", mode_reason: "Company — reader.listCompanies() / companyByDomain(); Zendesk organizations ARE the customer companies. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Organizations" }
      - { method: "GET", path: "/api/v2/organizations/{organization_id}", area: "organizations", tier: 1, status: "green", mode: "derive", mode_reason: "Company — reader.listCompanies() / companyByDomain(); Zendesk organizations ARE the customer companies. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Organizations" }
      - { method: "GET", path: "/api/v2/organizations/{organization_id}/merges", area: "organizations", tier: 1, status: "green", mode: "derive", mode_reason: "Company — reader.listCompanies() / companyByDomain(); Zendesk organizations ARE the customer companies. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): EMPTY: nothing in this universe was ever merged", mode_reviewed: "2026-09-04", tag: "Organizations" }
      - { method: "GET", path: "/api/v2/organizations/{organization_id}/organization_memberships", area: "organizations", tier: 1, status: "green", mode: "derive", mode_reason: "Contact -> Company — reader.contactsFor(company). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Organization Memberships" }
      - { method: "GET", path: "/api/v2/organizations/{organization_id}/related", area: "organizations", tier: 1, status: "green", mode: "derive", mode_reason: "Company — reader.listCompanies() / companyByDomain(); Zendesk organizations ARE the customer companies. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Organizations" }
      - { method: "GET", path: "/api/v2/organizations/{organization_id}/requests", area: "requests", tier: 1, status: "green", mode: "derive", mode_reason: "SupportTicket read through its Contact requester — the end-user dialect over rows that exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Requests" }
      - { method: "GET", path: "/api/v2/organizations/{organization_id}/subscriptions", area: "organizations", tier: 3, status: "green", mode: "derive", mode_reason: "Contact -> Company, the same join Zendesk exposes as a subscription. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Organization Subscriptions" }
      - { method: "GET", path: "/api/v2/organizations/{organization_id}/tags", area: "tags", tier: 2, status: "green", mode: "derive", mode_reason: "SupportTicket.tags (the TicketTag enum) — the tag set derives from the tagged rows. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): EMPTY: canon tags TICKETS and nothing else, which is what the organization object's own `tags: []` says", mode_reviewed: "2026-09-04", tag: "Tags" }
      - { method: "GET", path: "/api/v2/organizations/{organization_id}/tickets", area: "tickets", tier: 1, status: "green", mode: "derive", mode_reason: "SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Tickets" }
      - { method: "GET", path: "/api/v2/organizations/{organization_id}/tickets/count", area: "tickets", tier: 1, status: "green", mode: "derive", mode_reason: "SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Tickets" }
      - { method: "GET", path: "/api/v2/organizations/{organization_id}/users", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Users" }
      - { method: "GET", path: "/api/v2/organizations/{organization_id}/users/count", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Users" }
      - { method: "GET", path: "/api/v2/organizations/autocomplete", area: "organizations", tier: 1, status: "green", mode: "derive", mode_reason: "Company — reader.listCompanies() / companyByDomain(); Zendesk organizations ARE the customer companies. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Organizations" }
      - { method: "GET", path: "/api/v2/organizations/count", area: "organizations", tier: 1, status: "green", mode: "derive", mode_reason: "Company — reader.listCompanies() / companyByDomain(); Zendesk organizations ARE the customer companies. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Organizations" }
      - { method: "GET", path: "/api/v2/organizations/search", area: "organizations", tier: 1, status: "green", mode: "derive", mode_reason: "Company — reader.listCompanies() / companyByDomain(); Zendesk organizations ARE the customer companies. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Organizations" }
      - { method: "GET", path: "/api/v2/organizations/show_many", area: "organizations", tier: 1, status: "green", mode: "derive", mode_reason: "Company — reader.listCompanies() / companyByDomain(); Zendesk organizations ARE the customer companies. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Organizations" }
      - { method: "GET", path: "/api/v2/problems", area: "tickets", tier: 1, status: "green", mode: "derive", mode_reason: "SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Tickets" }
      - { method: "POST", path: "/api/v2/problems/autocomplete", area: "tickets", tier: 1, status: "green", mode: "derive", mode_reason: "SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Tickets" }
      - { method: "GET", path: "/api/v2/queues", area: "routing", tier: 3, status: "green", mode: "empty", mode_reason: "omnichannel routing is an add-on this account has not enabled; no queue was ever defined; Zendesk's own answer for an account with none is `{\"queues\": []}` at 200, with no pagination envelope because the operation declares no paging parameters. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Omnichannel Routing Queues" }
      - { method: "GET", path: "/api/v2/queues/{queue_id}", area: "routing", tier: 3, status: "deferred", mode: "refuse", mode_reason: "omnichannel routing is an add-on this account has not enabled; no queue was ever defined, so no queue id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/queues` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Omnichannel Routing Queues" }
      - { method: "GET", path: "/api/v2/queues/definitions", area: "routing", tier: 3, status: "green", mode: "empty", mode_reason: "omnichannel routing is an add-on this account has not enabled; no queue was ever defined; Zendesk's own answer for an account with none is `{\"definitions\": {\"conditions_all\": [], \"conditions_any\": []}}` at 200 — the document's own shape with both lists empty rather than `{\"definitions\": {}}`, so a client that reads `definitions.conditions_all` gets an array. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Omnichannel Routing Queues" }
      - { method: "GET", path: "/api/v2/recipient_addresses", area: "support-addresses", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06: the account's one default support address, `support@<org.login>.zendesk.com` — Zendesk's own default form over the artifact's org login. The three verification statuses are derived and agree: a `*.zendesk.com` address satisfies SPF and domain verification by construction, while `cname_status` describes a custom domain and there is none", mode_reviewed: "2026-09-06", tag: "Support Addresses" }
      - { method: "GET", path: "/api/v2/recipient_addresses/{support_address_id}", area: "support-addresses", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06: the same address by id", mode_reviewed: "2026-09-06", tag: "Support Addresses" }
      - { method: "GET", path: "/api/v2/relationships/definitions/{target_type}", area: "custom-objects", tier: 3, status: "green", mode: "empty", mode_reason: "lookup relationships point at custom object types, and none is defined; Zendesk's own answer for an account with none is `{\"definitions\": {\"conditions_all\": [], \"conditions_any\": []}}` at 200 — the document's own shape with both lists empty rather than `{\"definitions\": {}}`, so a client that reads `definitions.conditions_all` gets an array. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Lookup Relationships" }
      - { method: "GET", path: "/api/v2/remote_authentications", area: "security", tier: 3, status: "green", mode: "empty", mode_reason: "no SSO/JWT remote authentication was ever configured on this account; Zendesk's own answer for an account with none is `{\"remote_authentications\": []}` at 200, with no pagination envelope because the operation declares no paging parameters. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Remote Authentications" }
      - { method: "GET", path: "/api/v2/requests", area: "requests", tier: 1, status: "green", mode: "derive", mode_reason: "SupportTicket read through its Contact requester — the end-user dialect over rows that exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): the AGENT view (every request on the desk), because this host has no signed-in principal; conformance asserts the collection matches the ticket collection row for row so nobody reads it as 'these are yours'", mode_reviewed: "2026-09-04", tag: "Requests" }
      - { method: "GET", path: "/api/v2/requests/{request_id}", area: "requests", tier: 1, status: "green", mode: "derive", mode_reason: "SupportTicket read through its Contact requester — the end-user dialect over rows that exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Requests" }
      - { method: "GET", path: "/api/v2/requests/{request_id}/comments", area: "requests", tier: 1, status: "green", mode: "derive", mode_reason: "SupportTicket read through its Contact requester — the end-user dialect over rows that exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): PUBLIC comments only — the end-user lens is a real projection, not an alias, and canon's `is_public` is Zendesk's `public`", mode_reviewed: "2026-09-04", tag: "Requests" }
      - { method: "GET", path: "/api/v2/requests/{request_id}/comments/{ticket_comment_id}", area: "requests", tier: 1, status: "green", mode: "derive", mode_reason: "SupportTicket read through its Contact requester — the end-user dialect over rows that exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): PUBLIC comments only, per the end-user lens", mode_reviewed: "2026-09-04", tag: "Requests" }
      - { method: "GET", path: "/api/v2/requests/ccd", area: "requests", tier: 1, status: "green", mode: "derive", mode_reason: "SupportTicket read through its Contact requester — the end-user dialect over rows that exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): EMPTY, agreeing with every ticket's own `collaborator_ids: []`", mode_reviewed: "2026-09-04", tag: "Requests" }
      - { method: "GET", path: "/api/v2/requests/open", area: "requests", tier: 1, status: "green", mode: "derive", mode_reason: "SupportTicket read through its Contact requester — the end-user dialect over rows that exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Requests" }
      - { method: "GET", path: "/api/v2/requests/search", area: "requests", tier: 1, status: "green", mode: "derive", mode_reason: "SupportTicket read through its Contact requester — the end-user dialect over rows that exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Requests" }
      - { method: "GET", path: "/api/v2/requests/solved", area: "requests", tier: 1, status: "green", mode: "derive", mode_reason: "SupportTicket read through its Contact requester — the end-user dialect over rows that exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Requests" }
      - { method: "GET", path: "/api/v2/resource_collections", area: "resource-collections", tier: 3, status: "green", mode: "empty", mode_reason: "resource collections are an app-framework surface with nothing installed on this account; Zendesk's own answer for an account with none is `{\"resource_collections\": [], \"count\": 0, \"next_page\": null, \"previous_page\": null}` at 200, and the cursor envelope when the caller asks for that dialect. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Resource Collections" }
      - { method: "GET", path: "/api/v2/resource_collections/{resource_collection_id}", area: "resource-collections", tier: 3, status: "deferred", mode: "refuse", mode_reason: "resource collections are an app-framework surface with nothing installed on this account, so no resource collection id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/resource_collections` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Resource Collections" }
      - { method: "GET", path: "/api/v2/routing/agents/{user_id}/instance_values", area: "routing", tier: 3, status: "green", mode: "empty", mode_reason: "skill-based routing is an add-on this account has not enabled, so its attributes, definitions and per-ticket requirements are all empty collections; Zendesk's own answer for an account with none is `{\"attribute_values\": []}` at 200 for a parent this universe really has, and its ordinary entity 404 for one it does not — a cheerful empty for an id nobody has would contradict the by-id route beside it. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Skill Based Routing" }
      - { method: "GET", path: "/api/v2/routing/agents/instance_values", area: "routing", tier: 3, status: "green", mode: "empty", mode_reason: "skill-based routing is an add-on this account has not enabled, so its attributes, definitions and per-ticket requirements are all empty collections; Zendesk's own answer for an account with none is `{\"instance_values\": [], \"count\": 0, \"next_page\": null, \"previous_page\": null}` at 200, and the cursor envelope when the caller asks for that dialect. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Skill Based Routing" }
      - { method: "GET", path: "/api/v2/routing/attributes", area: "routing", tier: 3, status: "green", mode: "empty", mode_reason: "skill-based routing is an add-on this account has not enabled, so its attributes, definitions and per-ticket requirements are all empty collections; Zendesk's own answer for an account with none is `{\"attributes\": [], \"count\": 0, \"next_page\": null, \"previous_page\": null}` at 200, and the cursor envelope when the caller asks for that dialect. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Skill Based Routing" }
      - { method: "GET", path: "/api/v2/routing/attributes/{attribute_id}", area: "routing", tier: 3, status: "deferred", mode: "refuse", mode_reason: "skill-based routing is an add-on this account has not enabled, so its attributes, definitions and per-ticket requirements are all empty collections, so no routing attribute id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/routing/attributes` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Skill Based Routing" }
      - { method: "GET", path: "/api/v2/routing/attributes/{attribute_id}/values", area: "routing", tier: 3, status: "deferred", mode: "refuse", mode_reason: "skill-based routing is an add-on this account has not enabled, so its attributes, definitions and per-ticket requirements are all empty collections, so no routing attribute id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/routing/attributes` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Skill Based Routing" }
      - { method: "GET", path: "/api/v2/routing/attributes/{attribute_id}/values/{attribute_value_id}", area: "routing", tier: 3, status: "deferred", mode: "refuse", mode_reason: "skill-based routing is an add-on this account has not enabled, so its attributes, definitions and per-ticket requirements are all empty collections, so no routing attribute id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/routing/attributes` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Skill Based Routing" }
      - { method: "GET", path: "/api/v2/routing/attributes/definitions", area: "routing", tier: 3, status: "green", mode: "empty", mode_reason: "skill-based routing is an add-on this account has not enabled, so its attributes, definitions and per-ticket requirements are all empty collections; Zendesk's own answer for an account with none is `{\"definitions\": {\"conditions_all\": [], \"conditions_any\": []}}` at 200 — the document's own shape with both lists empty rather than `{\"definitions\": {}}`, so a client that reads `definitions.conditions_all` gets an array. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Skill Based Routing" }
      - { method: "GET", path: "/api/v2/routing/requirements/fulfilled", area: "routing", tier: 3, status: "green", mode: "empty", mode_reason: "skill-based routing is an add-on this account has not enabled, so its attributes, definitions and per-ticket requirements are all empty collections; Zendesk's own answer for an account with none is `{\"fulfilled_ticket_ids\": []}` at 200, with no pagination envelope because the operation declares no paging parameters. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Skill Based Routing" }
      - { method: "GET", path: "/api/v2/routing/tickets/{ticket_id}/instance_values", area: "routing", tier: 3, status: "green", mode: "empty", mode_reason: "skill-based routing is an add-on this account has not enabled, so its attributes, definitions and per-ticket requirements are all empty collections; Zendesk's own answer for an account with none is `{\"attribute_values\": []}` at 200 for a parent this universe really has, and its ordinary entity 404 for one it does not — a cheerful empty for an id nobody has would contradict the by-id route beside it. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Skill Based Routing" }
      - { method: "GET", path: "/api/v2/satisfaction_ratings", area: "satisfaction", tier: 2, status: "green", mode: "derive", mode_reason: "SupportTicket.satisfaction (the SatisfactionScore enum). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Satisfaction Ratings" }
      - { method: "GET", path: "/api/v2/satisfaction_ratings/{satisfaction_rating_id}", area: "satisfaction", tier: 2, status: "green", mode: "derive", mode_reason: "SupportTicket.satisfaction (the SatisfactionScore enum). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Satisfaction Ratings" }
      - { method: "GET", path: "/api/v2/satisfaction_ratings/count", area: "satisfaction", tier: 2, status: "green", mode: "derive", mode_reason: "SupportTicket.satisfaction (the SatisfactionScore enum). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Satisfaction Ratings" }
      - { method: "GET", path: "/api/v2/satisfaction_reasons", area: "satisfaction", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06 as a COMPUTED empty, and the contradiction check settled it: this host serves satisfaction RATINGS and not one cites a reason, because `shapeSatisfactionRating` emits no `reason` field (canon carries a score and no free-text survey answer). A catalog with rows beside ratings that cite none would be explanations nobody ever chose. The conformance entry asserts `reasons.length === the number of ratings citing one`", mode_reviewed: "2026-09-06", tag: "Satisfaction Reasons" }
      - { method: "GET", path: "/api/v2/satisfaction_reasons/{satisfaction_reason_id}", area: "satisfaction", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06 as an ENTITY MISS: no reason is configured, so no id resolves", mode_reviewed: "2026-09-06", tag: "Satisfaction Reasons" }
      - { method: "GET", path: "/api/v2/saved_searches", area: "search", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: `listSavedSearches()` with the `query` string COMPOSED from `conditionsFor(search)` — canon deliberately stores no query, because Zendesk's search syntax does not belong in a table every provider shares, and this renderer is the layer that knows the syntax. The id is a deterministic v4 UUID, which the document requires it to be. Scoped to the whole account rather than to a caller, because this host has no signed-in principal", mode_reviewed: "2026-09-07", tag: "Saved Searches" }
      - { method: "GET", path: "/api/v2/search", area: "search", tier: 1, status: "green", mode: "derive", mode_reason: "the SupportTicket / Contact / Company rows the canon now carries; only the query grammar is renderer work. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): a stated subset of Zendesk's query grammar (`type:`, `status:`, `priority:`, `tags:`, bare words); an unparsed term narrows rather than widens, so an unsupported query returns fewer results and never a wrong superset", mode_reviewed: "2026-09-04", tag: "Search" }
      - { method: "GET", path: "/api/v2/search/count", area: "search", tier: 1, status: "green", mode: "derive", mode_reason: "the SupportTicket / Contact / Company rows the canon now carries; only the query grammar is renderer work. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): the count of the same grammar's hits", mode_reviewed: "2026-09-04", tag: "Search" }
      - { method: "GET", path: "/api/v2/search/export", area: "search", tier: 1, status: "green", mode: "derive", mode_reason: "the SupportTicket / Contact / Company rows the canon now carries; only the query grammar is renderer work. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): cursor-paged only, which is a property of this endpoint rather than of the request", mode_reviewed: "2026-09-04", tag: "Search" }
      - { method: "GET", path: "/api/v2/security_settings", area: "security", tier: 3, status: "green", mode: "derive", mode_reason: "every real Zendesk account HAS a security posture, so neither a 403 nor an empty is available: the refuse wave's owner-only proposal was contradicted twice over (the operation's `Allowed For` says Admins while /api/v2/users/me answers an admin, and an absence claim would be false about any account). SERVED 2026-09-06 (coverage/reviews/2026-09-06-zendesk-rulings.md) in SecuritySettingsObject's shape, schema-declared fields only. Sixteen leaf values are DERIVED from facts this universe or this host already publishes - the whole `ip` block from the standing posture that any credential from any address is accepted, the external-identity half of `authentication` from an account that configured no IdP and whose OAuth registry is served empty, the assumption trio from a universe with no Zendesk-support relationship, and `two_factor_last_update` from the org's own creation instant (reader-derived, never Date.now()). The remainder are the PINNED DOCUMENT'S OWN published values for knobs nobody in this universe ever turned - the `EN_US` provenance rule on this same renderer, applied one family over - and they are flagged for a future capture in the review doc. `derive` and not `generate` because the row is SERVED and MODES' own vocabulary reserves `generate` for canon that does not exist (the CircleCI 2026-09-05 precedent)", mode_reviewed: "2026-09-06", tag: "Security Settings" }
      - { method: "GET", path: "/api/v2/sessions", area: "sessions", tier: 3, status: "green", mode: "empty", mode_reason: "nobody in this universe has ever signed in - this replica authenticates a caller with an API key rather than a session - so the session list is a real collection with nothing in it. The refuse wave sent the proposal back because its own ruled reason argued EMPTINESS rather than refusal, and because the operation's description says an agent or end user gets `only the sessions of the user making the request`: it always answers, scoped (founder ruling 2026-09-06, coverage/reviews/2026-09-06-zendesk-rulings.md)", mode_reviewed: "2026-09-06", tag: "Sessions" }
      - { method: "GET", path: "/api/v2/sharing_agreements", area: "sharing", tier: 3, status: "green", mode: "empty", mode_reason: "this account shares tickets with no other Zendesk account; Zendesk's own answer for an account with none is `{\"sharing_agreements\": []}` at 200, with no pagination envelope because the operation declares no paging parameters. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Sharing Agreements" }
      - { method: "GET", path: "/api/v2/sharing_agreements/{sharing_agreement_id}", area: "sharing", tier: 3, status: "deferred", mode: "refuse", mode_reason: "this account shares tickets with no other Zendesk account, so no sharing agreement id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/sharing_agreements` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Sharing Agreements" }
      - { method: "GET", path: "/api/v2/skips", area: "tickets", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: `listTicketSkips()` / `skipsForTicket()` / `skipsForAgent()`, each carrying the whole skipped TICKET the way upstream does. The skipping user is always an agent — skipping is a Play-mode act — and an end user's list is an honest empty rather than a 404", mode_reviewed: "2026-09-07", tag: "Ticket Skips" }
      - { method: "GET", path: "/api/v2/slas/policies", area: "sla", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06, and the strongest derivation on this host: canon has been measuring these tickets against an SLA policy since hello-14. `SupportTicket.slaBreached` is derived from `firstResponseOffset` against `FIRST_RESPONSE_TARGET_SEC`, which IS a Zendesk policy — four `first_reply_time` targets, one per priority. The conformance entry recomputes the artifact's own `sla_breached` column from the targets THIS RESPONSE publishes, on every ticket, so the policy advertised here is provably the policy the desk was measured against. Zendesk counts minutes and canon counts seconds; the round trip is asserted", mode_reviewed: "2026-09-06", tag: "SLA Policies" }
      - { method: "GET", path: "/api/v2/slas/policies/{sla_policy_id}", area: "sla", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06: the one policy by id", mode_reviewed: "2026-09-06", tag: "SLA Policies" }
      - { method: "GET", path: "/api/v2/slas/policies/definitions", area: "sla", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06: the filter fields a policy on this account could be written against, derived from the ticket fields this host serves and the groups on its roster — the conformance entry asserts the SLA filter and the ticket-field catalog offer the same choices for the same field", mode_reviewed: "2026-09-06", tag: "SLA Policies" }
      - { method: "GET", path: "/api/v2/suspended_tickets", area: "suspended-tickets", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: `listSuspendedTickets()`, newest first. The senders are from OUTSIDE the org by construction, so no `author.id` is emitted and every address resolves in RFC 2606 `.invalid`/`.example`; where a sender quoted a ticket, it is a ticket this host serves", mode_reviewed: "2026-09-07", tag: "Suspended Tickets" }
      - { method: "GET", path: "/api/v2/suspended_tickets/{id}", area: "suspended-tickets", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: `suspendedTicket()` under the SINGULAR key. The document declares `SuspendedTicketsResponse` (plural) on an operation called \"Show Suspended Ticket\"; both envelopes validate, so the operation's own meaning breaks the tie — and `node-zendesk` unwraps the singular (DECISIONS 2026-09-07)", mode_reviewed: "2026-09-07", tag: "Suspended Tickets" }
      - { method: "GET", path: "/api/v2/tags", area: "tags", tier: 2, status: "green", mode: "derive", mode_reason: "SupportTicket.tags (the TicketTag enum) — the tag set derives from the tagged rows. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Tags" }
      - { method: "GET", path: "/api/v2/tags/count", area: "tags", tier: 2, status: "green", mode: "derive", mode_reason: "SupportTicket.tags (the TicketTag enum) — the tag set derives from the tagged rows. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): the size of the tag vocabulary in use, stamped with the universe's own clock rather than Date.now()", mode_reviewed: "2026-09-04", tag: "Tags" }
      - { method: "GET", path: "/api/v2/target_failures", area: "targets", tier: 3, status: "green", mode: "empty", mode_reason: "no target exists, so none has failed; Zendesk's own answer for an account with none is `{\"target_failures\": []}` at 200, with no pagination envelope because the operation declares no paging parameters. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Target Failures" }
      - { method: "GET", path: "/api/v2/target_failures/{target_failure_id}", area: "targets", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no target exists, so none has failed, so no target failure id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/target_failures` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Target Failures" }
      - { method: "GET", path: "/api/v2/targets", area: "targets", tier: 3, status: "green", mode: "empty", mode_reason: "no HTTP or email target was ever configured; targets are deprecated upstream in favour of webhooks; Zendesk's own answer for an account with none is `{\"targets\": []}` at 200, with no pagination envelope because the operation declares no paging parameters. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Targets" }
      - { method: "GET", path: "/api/v2/targets/{target_id}", area: "targets", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no HTTP or email target was ever configured; targets are deprecated upstream in favour of webhooks, so no target id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/targets` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Targets" }
      - { method: "GET", path: "/api/v2/task_list_templates", area: "task-lists", tier: 3, status: "green", mode: "empty", mode_reason: "no task-list template was ever authored; Zendesk's own answer for an account with none is `{\"task_list_templates\": [], \"links\": {\"next\": null, \"prev\": null}, \"meta\": {\"has_more\": false, \"after_cursor\": null, \"before_cursor\": null}}` at 200 — this operation declares ONLY the cursor envelope, and both halves of each go null at the end of a collection, which for an empty one is every page. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Task List Templates" }
      - { method: "GET", path: "/api/v2/task_list_templates/{task_list_template_id}", area: "task-lists", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no task-list template was ever authored, so no task list template id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/task_list_templates` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Task List Templates" }
      - { method: "GET", path: "/api/v2/task_list_templates/{task_list_template_id}/tasks", area: "task-lists", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no task-list template was ever authored, so no task list template id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/task_list_templates` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Task List Templates" }
      - { method: "GET", path: "/api/v2/task_lists/{task_list_id}", area: "task-lists", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no agent ever added a checklist to a ticket in this universe, so no task list id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/tickets/{ticket_id}/task_lists` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Task Lists" }
      - { method: "GET", path: "/api/v2/task_lists/{task_list_id}/task_items", area: "task-lists", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no agent ever added a checklist to a ticket in this universe, so no task list id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/tickets/{ticket_id}/task_lists` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Task Lists" }
      - { method: "GET", path: "/api/v2/task_lists/{task_list_id}/task_items/{task_item_id}", area: "task-lists", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no agent ever added a checklist to a ticket in this universe, so no task list id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/tickets/{ticket_id}/task_lists` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Task Lists" }
      - { method: "GET", path: "/api/v2/ticket_audits", area: "tickets", tier: 1, status: "green", mode: "derive", mode_reason: "TicketFieldChange — reader.ticketChangesFor(ticket); the canon's own doc calls these Zendesk Ticket Audits events. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): the audits assembled from TicketComment and TicketFieldChange, in the document's own third envelope (top-level cursors); the four cursor keys are OMITTED rather than null at the ends, because this response types them as plain `string`", mode_reviewed: "2026-09-04", tag: "Ticket Audits" }
      - { method: "GET", path: "/api/v2/ticket_content_pins", area: "tickets", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07, AMENDED 2026-09-12: `listContentPins()` joined to `listHelpCenterArticles()`. `content_type` is `help_center_article` rather than the document's single `external_content` example, because what these agents pinned is an article in this account's OWN help centre — which hello-15 gave it, and which the brand row now says it has. The 2026-09-12 re-pin (coverage/provider-pins.yaml, zendesk.rest) brought an upstream CORRECTION to `TicketContentPin`: `account_id` and `ticket_id` are now `type: integer` with the examples `124125123` and `5`, where the 2026-09-04 document typed every field of the schema as a string. This row served four strings and now serves two strings (`id`, `content_id` — ULIDs upstream) and two integers; `account_id` mints in a new `account` id band and `ticket_id` is the number `/api/v2/tickets/{id}` is addressed by", mode_reviewed: "2026-09-12", tag: "Ticket Content Pins" }
      - { method: "GET", path: "/api/v2/ticket_fields", area: "ticket-fields", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06 (coverage/reviews/2026-09-06-zendesk-configuration.md): Zendesk's SEVEN system ticket fields, whose `type` values are exactly the fields `shapeTicket` already serves. The three that carry `system_field_options` read canon's own enums, and both `sub_type_id` values are COMPUTED from the tickets — the document says a `status` sub type of 1 ADDS On-Hold and a `priority` sub type of 1 REMOVES Low and Urgent, so each number is read off whether this desk uses those values. BARE envelope: `TicketFieldsResponse` declares no pagination property although the operation declares cursor parameters, and the SCHEMA decides", mode_reviewed: "2026-09-06", tag: "Ticket Fields" }
      - { method: "GET", path: "/api/v2/ticket_fields/{ticket_field_id}", area: "ticket-fields", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06: one system ticket field, asserted identical to the row the list serves", mode_reviewed: "2026-09-06", tag: "Ticket Fields" }
      - { method: "GET", path: "/api/v2/ticket_fields/{ticket_field_id}/options", area: "ticket-fields", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06: the CUSTOM option list, which is empty as a PROJECTION of every field on this account being a system field (`removable: false` on all seven) — the document presents `custom_field_options` only for a custom multiselect or tagger, and a system field's choices ride on the object itself under `system_field_options`. The conformance entry asserts that link, never the emptiness", mode_reviewed: "2026-09-06", tag: "Ticket Fields" }
      - { method: "GET", path: "/api/v2/ticket_fields/{ticket_field_id}/options/{ticket_field_option_id}", area: "ticket-fields", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06 as an ENTITY MISS: there is no custom ticket field, so there is no custom option for an id to name, and a 404 is the correct answer for every id forever — the `/deleted_users/{deleted_user_id}` reading already established on this host", mode_reviewed: "2026-09-06", tag: "Ticket Fields" }
      - { method: "GET", path: "/api/v2/ticket_fields/count", area: "ticket-fields", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06: the count of the system ticket fields, asserted equal to the list length rather than to a number", mode_reviewed: "2026-09-06", tag: "Ticket Fields" }
      - { method: "GET", path: "/api/v2/ticket_fields/show_many", area: "ticket-fields", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06: the same fields by id. ALWAYS the offset envelope — `TicketFieldsShowManyResponse` is the one schema in this family with `additionalProperties: false`, so a cursor envelope's `meta`/`links` would fail the document outright", mode_reviewed: "2026-09-06", tag: "Ticket Fields" }
      - { method: "GET", path: "/api/v2/ticket_form_statuses", area: "ticket-forms", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06: a TicketFormStatus is a RESTRICTION (one form narrowing itself to one custom status), and the account's one form restricts nothing — so the list is the projection of the forms beside it. Also the only answer the document can express: `TicketFormStatusesResponse` carries `maxItems: 1`, a vendor bug mirrored rather than fixed", mode_reviewed: "2026-09-06", tag: "Ticket Form Statuses" }
      - { method: "GET", path: "/api/v2/ticket_form_statuses/show_many", area: "ticket-forms", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06: as above", mode_reviewed: "2026-09-06", tag: "Ticket Form Statuses" }
      - { method: "GET", path: "/api/v2/ticket_forms", area: "ticket-forms", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06: the account's one ticket form, whose `ticket_field_ids` IS the ticket-field list. The NAME is the account's own name from the artifact, not Zendesk's product default — the document establishes that a default form exists (`fallback_to_default`) but publishes no name for it, and a proper noun is the one thing a renderer may not author", mode_reviewed: "2026-09-06", tag: "Ticket Forms" }
      - { method: "GET", path: "/api/v2/ticket_forms/{ticket_form_id}", area: "ticket-forms", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06: one ticket form; an unknown id is the entity 404", mode_reviewed: "2026-09-06", tag: "Ticket Forms" }
      - { method: "GET", path: "/api/v2/ticket_forms/{ticket_form_id}/ticket_form_statuses", area: "ticket-forms", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06: as above, scoped to the one form; an unknown form id is the entity 404 rather than an empty list", mode_reviewed: "2026-09-06", tag: "Ticket Forms" }
      - { method: "GET", path: "/api/v2/ticket_forms/show_many", area: "ticket-forms", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06: the same form by id", mode_reviewed: "2026-09-06", tag: "Ticket Forms" }
      - { method: "GET", path: "/api/v2/ticket_metrics", area: "ticket-metrics", tier: 2, status: "green", mode: "derive", mode_reason: "SupportTicket.firstResponseOffset / solvedOffset / reopenCount — the timings Zendesk publishes as a metric object, already in canon. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Ticket Metrics" }
      - { method: "GET", path: "/api/v2/ticket_metrics/{ticket_metric_id}", area: "ticket-metrics", tier: 2, status: "green", mode: "derive", mode_reason: "SupportTicket.firstResponseOffset / solvedOffset / reopenCount — the timings Zendesk publishes as a metric object, already in canon. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Ticket Metrics" }
      - { method: "GET", path: "/api/v2/tickets", area: "tickets", tier: 1, status: "green", mode: "derive", mode_reason: "SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Tickets" }
      - { method: "GET", path: "/api/v2/tickets/{ticket_id}", area: "tickets", tier: 1, status: "green", mode: "derive", mode_reason: "SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Tickets" }
      - { method: "GET", path: "/api/v2/tickets/{ticket_id}/audits", area: "tickets", tier: 1, status: "green", mode: "derive", mode_reason: "TicketFieldChange — reader.ticketChangesFor(ticket); the canon's own doc calls these Zendesk Ticket Audits events. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Ticket Audits" }
      - { method: "GET", path: "/api/v2/tickets/{ticket_id}/audits/{ticket_audit_id}", area: "tickets", tier: 1, status: "green", mode: "derive", mode_reason: "TicketFieldChange — reader.ticketChangesFor(ticket); the canon's own doc calls these Zendesk Ticket Audits events. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Ticket Audits" }
      - { method: "GET", path: "/api/v2/tickets/{ticket_id}/audits/count", area: "tickets", tier: 1, status: "green", mode: "derive", mode_reason: "TicketFieldChange — reader.ticketChangesFor(ticket); the canon's own doc calls these Zendesk Ticket Audits events. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Ticket Audits" }
      - { method: "GET", path: "/api/v2/tickets/{ticket_id}/collaborators", area: "tickets", tier: 1, status: "green", mode: "derive", mode_reason: "SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): EMPTY, and asserted to AGREE with the ticket object's own `collaborator_ids: []`", mode_reviewed: "2026-09-04", tag: "Tickets" }
      - { method: "GET", path: "/api/v2/tickets/{ticket_id}/comments", area: "tickets", tier: 1, status: "green", mode: "derive", mode_reason: "TicketComment — reader.commentsFor(ticket); canon carries `publicComment`, which is Zendesk's `public` verbatim. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Ticket Comments" }
      - { method: "GET", path: "/api/v2/tickets/{ticket_id}/comments/count", area: "tickets", tier: 1, status: "green", mode: "derive", mode_reason: "TicketComment — reader.commentsFor(ticket); canon carries `publicComment`, which is Zendesk's `public` verbatim. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Ticket Comments" }
      - { method: "GET", path: "/api/v2/tickets/{ticket_id}/conversation_log", area: "channels", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: `conversationFor(ticket)`. A `Comment` event IS one of the ticket's own comments (canon's `ticketComment` join), and since PR C (#384) removed the second rendering the log and the thread carry ONE text for one message — asserted per event rather than worked around, which is what the first cut of this wave had to do. A ticket that did not arrive through messaging has an empty log rather than a 404", mode_reviewed: "2026-09-07", tag: "Conversation Log" }
      - { method: "GET", path: "/api/v2/tickets/{ticket_id}/email_ccs", area: "tickets", tier: 1, status: "green", mode: "derive", mode_reason: "SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): EMPTY, and asserted to AGREE with the ticket object's own `email_cc_ids: []`", mode_reviewed: "2026-09-04", tag: "Tickets" }
      - { method: "GET", path: "/api/v2/tickets/{ticket_id}/followers", area: "tickets", tier: 1, status: "green", mode: "derive", mode_reason: "SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): EMPTY, and asserted to AGREE with the ticket object's own `follower_ids: []`", mode_reviewed: "2026-09-04", tag: "Tickets" }
      - { method: "GET", path: "/api/v2/tickets/{ticket_id}/group_slas/policy_metrics", area: "sla", tier: 2, status: "green", mode: "empty", mode_reason: "the group-SLA policy list is SERVED on this same host and this account defines none, so no ticket can carry a group-SLA metric. The empty rests on an answer a caller can already read rather than on a claim this row makes: `/api/v2/group_slas/policies` answers the empty collection because a group SLA sets a group-OWNERSHIP target and canon carries none for any team (`FIRST_RESPONSE_TARGET_SEC` is the only support target in the model, which the served `/api/v2/slas/policies` states in the same breath). Zendesk's own answer for a ticket with none is `{\"policy_metrics\": []}` at 200, with no pagination envelope because the operation declares no paging parameters - and the ticket is GUARDED: an id this universe does not have is the ordinary entity 404, never a cheerful empty, because a 200 there would contradict `GET /api/v2/tickets/{ticket_id}` answering 404 beside it. ITS FIRST-REPLY SIBLING IS NOT EMPTY and the pair is the point: `/api/v2/tickets/{ticket_id}/slas/policy_metrics` serves ONE metric, because the account's one SLA policy does set a first-reply target - two adjacent rows, two different answers, each true of the policy it reports, and the conformance entry drives both so a later wave cannot make them agree by habit. NOT ONE OF THE EIGHTY: this row arrived with the 2026-09-12 spec re-pin, and the wave that served its two `derive` siblings on 2026-09-13 PROPOSED it rather than arming it, because an `empty` is a founder ruling and a wave that wrote both would be reviewing its own empty. RULED by the founder 2026-09-13, as proposed", mode_reviewed: "2026-09-13", tag: "Group SLA Policies" }
      - { method: "GET", path: "/api/v2/tickets/{ticket_id}/incidents", area: "tickets", tier: 1, status: "green", mode: "derive", mode_reason: "SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): EMPTY, and asserted to AGREE with the ticket object's own `has_incidents: false` — canon links no ticket to a problem", mode_reviewed: "2026-09-04", tag: "Tickets" }
      - { method: "GET", path: "/api/v2/tickets/{ticket_id}/macros/{macro_id}/apply", area: "business-rules", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: the same projection against a real ticket from `ticketByZendeskId()`, so the result carries that ticket's id and url. A GET that mutates nothing, which is why it is a read upstream too", mode_reviewed: "2026-09-07", tag: "Macros" }
      - { method: "GET", path: "/api/v2/tickets/{ticket_id}/metric_events", area: "ticket-metrics", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-13, and it needed no ruling: `metricEventsFor()` (render.ts) ALREADY EXISTS and this same host already streams its output at `/api/v2/incremental/ticket_metric_events`, so this row is a re-envelope of a served answer rather than a new derivation. The operation declares its 200 as `additionalProperties` over arrays and its own summary says \"Returns a sorted list by metric instance, grouped by metric name\", so the map key is the metric and the value is that metric's events in instance-then-time order. TWO OF ZENDESK'S SIX METRICS are emitted and the other four are deliberately absent, which is the 2026-09-07 ruling on the incremental row unchanged: `reply_time` and `resolution_time` derive from canon's own instants (arrival, first response, solve), while `agent_work_time`, `pausable_update_time`, `periodic_update_time` and `requester_wait_time` are pause/resume integrals over a status history canon does not carry at that resolution and are not fabricated. A metric with no event carries NO KEY rather than an empty array — the map is what happened, not a template. The ticket is guarded: an id this universe does not have is the ordinary entity 404. Arrived `unclassified` with the 2026-09-12 spec re-pin and was never part of the founder's eighty", mode_reviewed: "2026-09-13", tag: "Ticket Metric Events" }
      - { method: "GET", path: "/api/v2/tickets/{ticket_id}/metrics", area: "ticket-metrics", tier: 2, status: "green", mode: "derive", mode_reason: "SupportTicket.firstResponseOffset / solvedOffset / reopenCount — the timings Zendesk publishes as a metric object, already in canon. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Ticket Metrics" }
      - { method: "GET", path: "/api/v2/tickets/{ticket_id}/related", area: "tickets", tier: 1, status: "green", mode: "derive", mode_reason: "SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): `jira_issue_ids` carries canon's `SupportTicket.issue`, the same tracker row Jira, Linear, GitHub and GitLab serve", mode_reviewed: "2026-09-04", tag: "Tickets" }
      - { method: "GET", path: "/api/v2/tickets/{ticket_id}/skips", area: "tickets", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: `listTicketSkips()` / `skipsForTicket()` / `skipsForAgent()`, each carrying the whole skipped TICKET the way upstream does. The skipping user is always an agent — skipping is a Play-mode act — and an end user's list is an honest empty rather than a 404", mode_reviewed: "2026-09-07", tag: "Ticket Skips" }
      - { method: "GET", path: "/api/v2/tickets/{ticket_id}/slas/policy_metrics", area: "sla", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-13, and it needed no ruling: this is the JOIN of two answers this host already publishes. `/api/v2/slas/policies` (ruled `derive` 2026-09-07) says which target applies — `first_reply_time` at `targetMinutes(priority)`, on a filter that matches every ticket because canon applies the same per-priority target to all of them — and the ticket carries the clock `breachesPolicy` already reads to reproduce the artifact's `sla_breached` column. Before this row a caller could read the policy and the breach flag on this host and NOT the row that relates them, which is the manifest disagreeing with the wire. ONE ENTRY, because the policy defines one metric. `stage` is `fulfilled` once the first response lands and `active` until then; `paused` cannot occur and that is DERIVED rather than overlooked, because pausing is measured against a SCHEDULE and `shapeSlaPolicy` already serves `business_hours: false` on every metric. `minutes` is the time REMAINING against the target, negative once past — the sense the document's own example carries (`minutes: -19` beside `stage: active`) — measured to the first response when there is one and to the universe's own ANCHOR when there is not, never to the wall clock, or a pinned host's answer would change every day. `days` and `hours` are OMITTED: they restate `minutes` more coarsely, the document's example omits them, and Zendesk publishes no rule for how it splits one into the other three, so writing one would be inventing a convention. Arrived `unclassified` with the 2026-09-12 spec re-pin and was never part of the founder's eighty", mode_reviewed: "2026-09-13", tag: "SLA Policies" }
      - { method: "GET", path: "/api/v2/tickets/{ticket_id}/tags", area: "tags", tier: 2, status: "green", mode: "derive", mode_reason: "SupportTicket.tags (the TicketTag enum) — the tag set derives from the tagged rows. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Tags" }
      - { method: "GET", path: "/api/v2/tickets/{ticket_id}/task_lists", area: "task-lists", tier: 3, status: "green", mode: "empty", mode_reason: "no agent ever added a checklist to a ticket in this universe; Zendesk's own answer for an account with none is `{\"task_lists\": [], \"count\": 0, \"next_page\": null, \"previous_page\": null}` at 200 for a ticket this universe really has, and its ordinary entity 404 for one it does not. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Task Lists" }
      - { method: "GET", path: "/api/v2/tickets/autocomplete", area: "tickets", tier: 1, status: "green", mode: "derive", mode_reason: "SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Tickets" }
      - { method: "GET", path: "/api/v2/tickets/count", area: "tickets", tier: 1, status: "green", mode: "derive", mode_reason: "SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Tickets" }
      - { method: "GET", path: "/api/v2/tickets/messaging/conversations/{conversation_id}/ticket", area: "tickets", tier: 1, status: "green", mode: "derive", mode_reason: "SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): the conversation id is canon's `SupportTicket.channel_ref` — the same Slack/Teams channel those hosts serve, so this is a real cross-provider join rather than a minted id", mode_reviewed: "2026-09-04", tag: "Tickets" }
      - { method: "GET", path: "/api/v2/tickets/recent", area: "tickets", tier: 1, status: "green", mode: "derive", mode_reason: "SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Tickets" }
      - { method: "GET", path: "/api/v2/tickets/show_many", area: "tickets", tier: 1, status: "green", mode: "derive", mode_reason: "SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Tickets" }
      - { method: "GET", path: "/api/v2/trigger_categories", area: "business-rules", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: `listTriggerCategories()`. The one row on this host whose pagination is not the caller's choice — the operation declares only the cursor `page` object, so the offset dialect is not on offer. The cursor keys are OMITTED at the ends rather than nulled, because `Pagination` types all four as plain strings with no `nullable`", mode_reviewed: "2026-09-07", tag: "Trigger Categories" }
      - { method: "GET", path: "/api/v2/trigger_categories/{trigger_category_id}", area: "business-rules", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: one category from the same accessor, with `?include=rule_counts` counting the triggers this host serves in it", mode_reviewed: "2026-09-07", tag: "Trigger Categories" }
      - { method: "GET", path: "/api/v2/triggers", area: "business-rules", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: `listSupportTriggers()` + `conditionsFor()` + `actionsFor()`, in EXECUTION order (`position`), each naming a category `/trigger_categories` serves. `category_id` is the STRING the document declares", mode_reviewed: "2026-09-07", tag: "Triggers" }
      - { method: "GET", path: "/api/v2/triggers/{trigger_id}", area: "business-rules", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: `listSupportTriggers()` + `conditionsFor()` + `actionsFor()`, in EXECUTION order (`position`), each naming a category `/trigger_categories` serves. `category_id` is the STRING the document declares", mode_reviewed: "2026-09-07", tag: "Triggers" }
      - { method: "GET", path: "/api/v2/triggers/{trigger_id}/revisions", area: "business-rules", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: `revisionsForTrigger(trigger)`, newest first, each carrying a SNAPSHOT from the revision's own row and a `diff` COMPUTED against the previous one — canon's schema says a diff is a pure function of two adjacent rows, so storing it would have been a second truth that drifts. The first revision carries no diff, because there is nothing to diff it against", mode_reviewed: "2026-09-07", tag: "Triggers" }
      - { method: "GET", path: "/api/v2/triggers/{trigger_id}/revisions/{trigger_revision_id}", area: "business-rules", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: one revision from the same accessor; the newest one's snapshot is asserted to equal the trigger's current definition", mode_reviewed: "2026-09-07", tag: "Triggers" }
      - { method: "GET", path: "/api/v2/triggers/active", area: "business-rules", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: `listSupportTriggers()` + `conditionsFor()` + `actionsFor()`, in EXECUTION order (`position`), each naming a category `/trigger_categories` serves. `category_id` is the STRING the document declares", mode_reviewed: "2026-09-07", tag: "Triggers" }
      - { method: "GET", path: "/api/v2/triggers/definitions", area: "business-rules", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: the trigger grammar COMPUTED from the account's own triggers, conditions and actions alike, with a human title beside every wire operator — which is what lets a caller reading `operator: \"value\"` find out on the same host that it means \"changed to\"", mode_reviewed: "2026-09-07", tag: "Triggers" }
      - { method: "GET", path: "/api/v2/triggers/limits", area: "business-rules", tier: 2, status: "deferred", mode: "generate", mode_reason: "PARTLY UNBLOCKED 2026-09-07, and still blocked on the half that matters: the `count` now follows from `listSupportTriggers()`, which this host serves — but the `limit` is a property of the account's Zendesk PLAN, and nothing in this repository records a plan for olympus-labs. Serving `{count, limit}` with an invented ceiling would be this replica asserting a price tier. Needs a CAPTURE or a founder ruling, not a canon entity. The row is deliberately left uncovered and a served test asserts it reaches the coverage 404 rather than being swallowed by `/triggers/{trigger_id}`", mode_reviewed: "2026-09-07", tag: "Triggers" }
      - { method: "GET", path: "/api/v2/triggers/search", area: "business-rules", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: `listSupportTriggers()` + `conditionsFor()` + `actionsFor()`, in EXECUTION order (`position`), each naming a category `/trigger_categories` serves. `category_id` is the STRING the document declares", mode_reviewed: "2026-09-07", tag: "Triggers" }
      - { method: "GET", path: "/api/v2/user_fields", area: "custom-fields", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06, ACCEPTED after being sent back the same day (coverage/reviews/2026-09-06-zendesk-field-catalogs.md): canon's `Contact` attributes (role, seniority, lifecycle stage, region, marketing opt-out) as Zendesk custom user fields, with every dropdown's options read off the DISTINCT values the contacts carry — an option list typed out here would be a second copy of a canon enum, free to drift silently. `shapeEndUser` fills the matching `user_fields` bag and `shapeAgent` answers null for every key, which is Zendesk's own model for a field that does not apply. The catalog and the records are two readings of one set and the conformance entry binds them", mode_reviewed: "2026-09-06", tag: "User Fields" }
      - { method: "GET", path: "/api/v2/user_fields/{user_field_id}", area: "custom-fields", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06: one definition, resolvable by id OR by key (the parameter is `oneOf [integer, string]`, and a client following a `key` from the list uses the second form)", mode_reviewed: "2026-09-06", tag: "User Fields" }
      - { method: "GET", path: "/api/v2/user_fields/{user_field_id}/options", area: "custom-fields", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06: the option list, which IS the distinct values the contacts carry", mode_reviewed: "2026-09-06", tag: "User Fields" }
      - { method: "GET", path: "/api/v2/user_fields/{user_field_id}/options/{user_field_option_id}", area: "custom-fields", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06: one option", mode_reviewed: "2026-09-06", tag: "User Fields" }
      - { method: "GET", path: "/api/v2/user_fields/show_many", area: "custom-fields", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06: the same definitions by KEY — `ShowManyUserFields` takes `keys` only, with no `ids` parameter unlike the ticket-field twin", mode_reviewed: "2026-09-06", tag: "User Fields" }
      - { method: "GET", path: "/api/v2/users", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Users" }
      - { method: "GET", path: "/api/v2/users/{user_id}", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Users" }
      - { method: "GET", path: "/api/v2/users/{user_id}/brand_agents", area: "brands", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06: one membership for an AGENT and none for an end user — a brand-agent record exists only for agents, and this host's own `role` field says which people those are. An unknown user id is the entity 404, not an empty list", mode_reviewed: "2026-09-06", tag: "Brand Agents" }
      - { method: "GET", path: "/api/v2/users/{user_id}/brand_agents/{brand_agent_id}", area: "brands", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-06: the same membership, scoped to its user", mode_reviewed: "2026-09-06", tag: "Brand Agents" }
      - { method: "GET", path: "/api/v2/users/{user_id}/compliance_deletion_statuses", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): EMPTY: nobody in this universe asked to be forgotten", mode_reviewed: "2026-09-04", tag: "Users" }
      - { method: "GET", path: "/api/v2/users/{user_id}/entitlements/full", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): EMPTY: the four entitlements are seats in products (Chat, Explore, Guide, Talk) this account does not license", mode_reviewed: "2026-09-04", tag: "Users" }
      - { method: "GET", path: "/api/v2/users/{user_id}/group_memberships", area: "groups", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser.team — the same join, in Zendesk's membership dialect. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Group Memberships" }
      - { method: "GET", path: "/api/v2/users/{user_id}/group_memberships/{group_membership_id}", area: "groups", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser.team — the same join, in Zendesk's membership dialect. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Group Memberships" }
      - { method: "GET", path: "/api/v2/users/{user_id}/groups", area: "groups", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser.team (the `sales`/`support`/`success` CrmTeam) — Zendesk's agent groups. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Groups" }
      - { method: "GET", path: "/api/v2/users/{user_id}/groups/count", area: "groups", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser.team (the `sales`/`support`/`success` CrmTeam) — Zendesk's agent groups. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Groups" }
      - { method: "GET", path: "/api/v2/users/{user_id}/identities", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "Contact — the email identity Zendesk models as a separate record is a field on the canon row. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "User Identities" }
      - { method: "GET", path: "/api/v2/users/{user_id}/identities/{user_identity_id}", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "Contact — the email identity Zendesk models as a separate record is a field on the canon row. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "User Identities" }
      - { method: "GET", path: "/api/v2/users/{user_id}/organization_memberships", area: "organizations", tier: 1, status: "green", mode: "derive", mode_reason: "Contact -> Company — reader.contactsFor(company). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Organization Memberships" }
      - { method: "GET", path: "/api/v2/users/{user_id}/organization_memberships/{organization_membership_id}", area: "organizations", tier: 1, status: "green", mode: "derive", mode_reason: "Contact -> Company — reader.contactsFor(company). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Organization Memberships" }
      - { method: "GET", path: "/api/v2/users/{user_id}/organization_subscriptions", area: "organizations", tier: 3, status: "green", mode: "derive", mode_reason: "Contact -> Company, the same join Zendesk exposes as a subscription. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Organization Subscriptions" }
      - { method: "GET", path: "/api/v2/users/{user_id}/organizations", area: "organizations", tier: 1, status: "green", mode: "derive", mode_reason: "Company — reader.listCompanies() / companyByDomain(); Zendesk organizations ARE the customer companies. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Organizations" }
      - { method: "GET", path: "/api/v2/users/{user_id}/organizations/count", area: "organizations", tier: 1, status: "green", mode: "derive", mode_reason: "Company — reader.listCompanies() / companyByDomain(); Zendesk organizations ARE the customer companies. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Organizations" }
      - { method: "GET", path: "/api/v2/users/{user_id}/password/requirements", area: "security", tier: 3, status: "green", mode: "derive", mode_reason: "every real account publishes the rules a new password must satisfy, so this row is served rather than refused: the refuse wave found its proposal contradicted by the document - its `Allowed For` is Agents and End Users, the only row of the seventeen with no Admin line, and it is scoped by the {user_id} in the PATH rather than by a signed-in principal. SERVED 2026-09-06 (coverage/reviews/2026-09-06-zendesk-rulings.md) COMPUTED from the password policy served at /api/v2/security_settings rather than transcribed - which matters, because the pinned document's two examples are NOT one coherent account (its security example says disallow_local_part_from_email false while its requirements example says `must be different from email address`). Only sentences the document itself publishes are emitted, so a policy knob with no published string produces no line rather than one this renderer authored", mode_reviewed: "2026-09-06", tag: "User Passwords" }
      - { method: "GET", path: "/api/v2/users/{user_id}/related", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Users" }
      - { method: "GET", path: "/api/v2/users/{user_id}/requests", area: "requests", tier: 1, status: "green", mode: "derive", mode_reason: "SupportTicket read through its Contact requester — the end-user dialect over rows that exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Requests" }
      - { method: "GET", path: "/api/v2/users/{user_id}/sessions", area: "sessions", tier: 3, status: "green", mode: "empty", mode_reason: "the LIST half of the by-id refusal below, and its reason argues emptiness rather than refusal: nobody in this universe has ever signed in, so this user's session list is a real collection with nothing in it. The {user_id} is still guarded - a session list for a person nobody has is a 404, not an empty list (founder ruling 2026-09-06, coverage/reviews/2026-09-06-zendesk-rulings.md)", mode_reviewed: "2026-09-06", tag: "Sessions" }
      - { method: "GET", path: "/api/v2/users/{user_id}/sessions/{session_id}", area: "sessions", tier: 3, status: "deferred", mode: "refuse", mode_reason: "nobody in this universe has ever signed in, so no session id can resolve for any user", mode_reviewed: "2026-09-05", tag: "Sessions" }
      - { method: "GET", path: "/api/v2/users/{user_id}/skips", area: "tickets", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: `listTicketSkips()` / `skipsForTicket()` / `skipsForAgent()`, each carrying the whole skipped TICKET the way upstream does. The skipping user is always an agent — skipping is a Play-mode act — and an end user's list is an honest empty rather than a 404", mode_reviewed: "2026-09-07", tag: "Ticket Skips" }
      - { method: "GET", path: "/api/v2/users/{user_id}/tags", area: "tags", tier: 2, status: "green", mode: "derive", mode_reason: "SupportTicket.tags (the TicketTag enum) — the tag set derives from the tagged rows. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): EMPTY: canon tags TICKETS and nothing else, which is what the user object's own `tags: []` says", mode_reviewed: "2026-09-04", tag: "Tags" }
      - { method: "GET", path: "/api/v2/users/{user_id}/tickets/assigned", area: "tickets", tier: 1, status: "green", mode: "derive", mode_reason: "SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Tickets" }
      - { method: "GET", path: "/api/v2/users/{user_id}/tickets/assigned/count", area: "tickets", tier: 1, status: "green", mode: "derive", mode_reason: "SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Tickets" }
      - { method: "GET", path: "/api/v2/users/{user_id}/tickets/ccd", area: "tickets", tier: 1, status: "green", mode: "derive", mode_reason: "SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): EMPTY, and it AGREES with every ticket's own `collaborator_ids: []` — canon puts nobody on a ticket but its requester and its assignee", mode_reviewed: "2026-09-04", tag: "Tickets" }
      - { method: "GET", path: "/api/v2/users/{user_id}/tickets/ccd/count", area: "tickets", tier: 1, status: "green", mode: "derive", mode_reason: "SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): 0, agreeing with the empty collection beside it", mode_reviewed: "2026-09-04", tag: "Tickets" }
      - { method: "GET", path: "/api/v2/users/{user_id}/tickets/followed", area: "tickets", tier: 1, status: "green", mode: "derive", mode_reason: "SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): EMPTY, agreeing with every ticket's own `follower_ids: []`", mode_reviewed: "2026-09-04", tag: "Tickets" }
      - { method: "GET", path: "/api/v2/users/{user_id}/tickets/requested", area: "tickets", tier: 1, status: "green", mode: "derive", mode_reason: "SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Tickets" }
      - { method: "GET", path: "/api/v2/users/autocomplete", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Users" }
      - { method: "POST", path: "/api/v2/users/autocomplete", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Users" }
      - { method: "GET", path: "/api/v2/users/count", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Users" }
      - { method: "GET", path: "/api/v2/users/me", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): the account OWNER (the first admin in canonical id order), because this host has no signed-in principal and an invented one would put somebody on the roster who is not on it", mode_reviewed: "2026-09-04", tag: "Users" }
      - { method: "GET", path: "/api/v2/users/me/oauth/clients", area: "oauth", tier: 3, status: "green", mode: "empty", mode_reason: "the caller's own OAuth clients - a registry nobody populated, answered 200 with the empty `clients` array. Same contradiction that took the account-wide registry off the refuse table: the operation's `Allowed For` says Admins and this host's /api/v2/users/me answers an admin (founder ruling 2026-09-06, coverage/reviews/2026-09-06-zendesk-rulings.md)", mode_reviewed: "2026-09-06", tag: "OAuth Clients" }
      - { method: "GET", path: "/api/v2/users/me/session", area: "sessions", tier: 3, status: "deferred", mode: "refuse", mode_reason: "this replica authenticates a caller with an API key rather than a session, so there is no currently authenticated session", mode_reviewed: "2026-09-05", tag: "Sessions" }
      - { method: "GET", path: "/api/v2/users/me/session/renew", area: "sessions", tier: 3, status: "excluded", mode: "read-only", mode_reason: "NOT A READ. RenewCurrentSession mints an authenticity token and extends the session's lifetime - its declared 200 is {authenticity_token}, a credential this replica would be manufacturing - so it belongs to invariant #3 rather than to any coverage mode. Its `Allowed For` is the widest in the block (Admins, Agents, End users), so nobody is entitlement-blocked either, which is why the refuse wave sent it back rather than arming it. The renderer's read-only boundary now reaches it through READ_AS_WRITE_TEMPLATES and answers Zendesk's own 403; the row is `excluded` and never joins the badge denominator, which is what this mode has meant since A0.1 and what no row in the fleet had used until now (founder ruling 2026-09-06, coverage/reviews/2026-09-06-zendesk-rulings.md)", mode_reviewed: "2026-09-06", tag: "Sessions" }
      - { method: "GET", path: "/api/v2/users/me/settings", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): an EMPTY settings object: every property the document declares under `settings` is a UI preference a human sets by clicking in the Zendesk web app, and nobody in this universe has ever opened it", mode_reviewed: "2026-09-04", tag: "Users" }
      - { method: "GET", path: "/api/v2/users/search", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Users" }
      - { method: "GET", path: "/api/v2/users/show_many", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)", mode_reviewed: "2026-09-04", tag: "Users" }
      - { method: "GET", path: "/api/v2/views", area: "views", tier: 1, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-07: `listSupportViews()` + `conditionsFor(view)`. The DEFINITION half is canon's (title, conditions, columns, sort); the EXECUTION half is computed at read time by evaluating those conditions against `listSupportTickets()` — one evaluator shared with `/views/{id}/count` and `POST /views/preview/count`, so the three can never disagree about which tickets are in a view. DOCUMENT SELF-CONTRADICTION, declared: `ViewObject.restriction` is typed `object` while its own description says \"Is null when everyone in the account can access it\" and the sibling `TriggerObject.restriction` IS declared nullable — so a view nobody restricted serves the null the description names and the row syncs to `deviation`", mode_reviewed: "2026-09-07", tag: "Views" }
      - { method: "GET", path: "/api/v2/views/{view_id}", area: "views", tier: 1, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-07: `listSupportViews()` + `conditionsFor(view)`. The DEFINITION half is canon's (title, conditions, columns, sort); the EXECUTION half is computed at read time by evaluating those conditions against `listSupportTickets()` — one evaluator shared with `/views/{id}/count` and `POST /views/preview/count`, so the three can never disagree about which tickets are in a view. DOCUMENT SELF-CONTRADICTION, declared: `ViewObject.restriction` is typed `object` while its own description says \"Is null when everyone in the account can access it\" and the sibling `TriggerObject.restriction` IS declared nullable — so a view nobody restricted serves the null the description names and the row syncs to `deviation`", mode_reviewed: "2026-09-07", tag: "Views" }
      - { method: "GET", path: "/api/v2/views/{view_id}/count", area: "views", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: the length of the ticket set the view's own conditions select, and equal to the length of `/views/{id}/tickets`. `fresh: true` is derived: the count is computed per request and there is no cache behind it to be stale", mode_reviewed: "2026-09-07", tag: "Views" }
      - { method: "GET", path: "/api/v2/views/{view_id}/execute", area: "views", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: the view's definition plus one ROW per selected ticket, carrying a cell for every column the view displays — the same tickets as `/views/{id}/tickets`, rendered through the view's own columns", mode_reviewed: "2026-09-07", tag: "Views" }
      - { method: "GET", path: "/api/v2/views/{view_id}/export", area: "views", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: the export JOB's status, which is what this operation returns upstream. This replica queues nothing, so the view is named and no export id is invented for a job that does not exist", mode_reviewed: "2026-09-07", tag: "Views" }
      - { method: "GET", path: "/api/v2/views/{view_id}/tickets", area: "views", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: the selected tickets, byte-identical to what `/api/v2/tickets/{id}` serves for each of them", mode_reviewed: "2026-09-07", tag: "Views" }
      - { method: "GET", path: "/api/v2/views/active", area: "views", tier: 1, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-07: `listSupportViews()` + `conditionsFor(view)`. The DEFINITION half is canon's (title, conditions, columns, sort); the EXECUTION half is computed at read time by evaluating those conditions against `listSupportTickets()` — one evaluator shared with `/views/{id}/count` and `POST /views/preview/count`, so the three can never disagree about which tickets are in a view. DOCUMENT SELF-CONTRADICTION, declared: `ViewObject.restriction` is typed `object` while its own description says \"Is null when everyone in the account can access it\" and the sibling `TriggerObject.restriction` IS declared nullable — so a view nobody restricted serves the null the description names and the row syncs to `deviation`", mode_reviewed: "2026-09-07", tag: "Views" }
      - { method: "GET", path: "/api/v2/views/compact", area: "views", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: the active views from `listSupportViews()` with the definition halves left off — compact means fewer FIELDS, which a test pins in both directions", mode_reviewed: "2026-09-07", tag: "Views" }
      - { method: "GET", path: "/api/v2/views/count", area: "views", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: the number of `listSupportViews()` rows in the shared `{count: {value, refreshed_at}}` envelope, stamped with the artifact's anchor rather than the wall clock", mode_reviewed: "2026-09-07", tag: "Views" }
      - { method: "GET", path: "/api/v2/views/count_many", area: "views", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: the per-view ticket counts for an `?ids=` list, each equal to what `/views/{id}/count` answers on its own — asserted, not assumed", mode_reviewed: "2026-09-07", tag: "Views" }
      - { method: "GET", path: "/api/v2/views/definitions", area: "views", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: the view grammar COMPUTED from `conditionsFor()` over the account's own views, plus the columns those views display — every sortable and groupable is asserted to be a column some view really shows", mode_reviewed: "2026-09-07", tag: "Views" }
      - { method: "POST", path: "/api/v2/views/preview/count", area: "views", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-07: a POST-as-READ (app.ts `POST_AS_READ`): the caller's own condition set evaluated by the SAME evaluator a saved view's is, so posting a view's own conditions counts exactly what that view counts", mode_reviewed: "2026-09-07", tag: "Views" }
      - { method: "GET", path: "/api/v2/views/search", area: "views", tier: 1, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-07: `listSupportViews()` + `conditionsFor(view)`. The DEFINITION half is canon's (title, conditions, columns, sort); the EXECUTION half is computed at read time by evaluating those conditions against `listSupportTickets()` — one evaluator shared with `/views/{id}/count` and `POST /views/preview/count`, so the three can never disagree about which tickets are in a view. DOCUMENT SELF-CONTRADICTION, declared: `ViewObject.restriction` is typed `object` while its own description says \"Is null when everyone in the account can access it\" and the sibling `TriggerObject.restriction` IS declared nullable — so a view nobody restricted serves the null the description names and the row syncs to `deviation`", mode_reviewed: "2026-09-07", tag: "Views" }
      - { method: "GET", path: "/api/v2/views/show_many", area: "views", tier: 1, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-07: `listSupportViews()` + `conditionsFor(view)`. The DEFINITION half is canon's (title, conditions, columns, sort); the EXECUTION half is computed at read time by evaluating those conditions against `listSupportTickets()` — one evaluator shared with `/views/{id}/count` and `POST /views/preview/count`, so the three can never disagree about which tickets are in a view. DOCUMENT SELF-CONTRADICTION, declared: `ViewObject.restriction` is typed `object` while its own description says \"Is null when everyone in the account can access it\" and the sibling `TriggerObject.restriction` IS declared nullable — so a view nobody restricted serves the null the description names and the row syncs to `deviation`", mode_reviewed: "2026-09-07", tag: "Views" }
      - { method: "GET", path: "/api/v2/workspaces", area: "workspaces", tier: 3, status: "green", mode: "empty", mode_reason: "no contextual workspace was ever configured; Zendesk's own answer for an account with none is `{\"workspaces\": [], \"count\": 0, \"next_page\": null, \"previous_page\": null}` at 200, and the cursor envelope when the caller asks for that dialect. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Workspaces" }
      - { method: "GET", path: "/api/v2/workspaces/{workspace_id}", area: "workspaces", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no contextual workspace was ever configured, so no workspace id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/workspaces` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means \"nothing\", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: \"admin\"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 (\"Approve all 80\"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.", mode_reviewed: "2026-09-13", tag: "Workspaces" }
    graphql: [] # no GraphQL API exists for this provider (REST-only)
  gitlab:
    rest:
      - { method: "GET", path: "/api/v4/admin_member_roles", area: "member roles", tier: 3, status: "deferred", mode: "refuse", mode_reason: "instance-level custom roles are a self-managed admin surface; GitLab.com answers 404 for them", mode_reviewed: "2026-09-01", tag: "Member roles", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/admin/active_context/connections", area: "active context", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Active context", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/admin/batched_background_migrations", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Batched background migrations", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/admin/batched_background_migrations/{id}", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Batched background migrations", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/admin/batched_background_operations", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Batched background operations", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/admin/batched_background_operations/{id}", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Batched background operations", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/admin/ci/variables", area: "variables", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "CI variables" }
      - { method: "GET", path: "/api/v4/admin/ci/variables/{key}", area: "variables", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "CI variables" }
      - { method: "GET", path: "/api/v4/admin/clusters", area: "clusters", tier: 3, status: "deferred", mode: "refuse", mode_reason: "certificate-based cluster integration is disabled on GitLab.com and removed upstream; mirroring it would advertise a surface no current client can reach", mode_reviewed: "2026-09-01", tag: "Clusters", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/admin/clusters/{cluster_id}", area: "clusters", tier: 3, status: "deferred", mode: "refuse", mode_reason: "certificate-based cluster integration is disabled on GitLab.com and removed upstream; mirroring it would advertise a surface no current client can reach", mode_reviewed: "2026-09-01", tag: "Clusters", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/admin/data_management/{model_name}", area: "data management", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Data management", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/admin/data_management/{model_name}/{record_identifier}", area: "data management", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Data management", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/admin/databases/{database_name}/dictionary/tables/{table_name}", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Database dictionary", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/admin/knowledge_graph/namespaces", area: "knowledge graph", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Knowledge graph", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/admin/migrations/pending", area: "migrations", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Migrations", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/admin/search/migrations", area: "search", tier: 2, status: "deferred", mode: "refuse", mode_reason: "Elasticsearch migrations and Zoekt shards describe the instance search cluster, are admin-only, and say nothing about the org", mode_reviewed: "2026-09-01", tag: "Search" }
      - { method: "GET", path: "/api/v4/admin/search/migrations/{migration_id}", area: "search", tier: 2, status: "deferred", mode: "refuse", mode_reason: "Elasticsearch migrations and Zoekt shards describe the instance search cluster, are admin-only, and say nothing about the org", mode_reviewed: "2026-09-01", tag: "Search" }
      - { method: "GET", path: "/api/v4/admin/security/compliance_policy_settings", area: "compliance policy settings", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Compliance policy settings", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/admin/zoekt/shards", area: "search", tier: 2, status: "deferred", mode: "refuse", mode_reason: "Elasticsearch migrations and Zoekt shards describe the instance search cluster, are admin-only, and say nothing about the org", mode_reviewed: "2026-09-01", tag: "Code search" }
      - { method: "GET", path: "/api/v4/admin/zoekt/shards/{node_id}/indexed_namespaces", area: "search", tier: 2, status: "deferred", mode: "refuse", mode_reason: "Elasticsearch migrations and Zoekt shards describe the instance search cluster, are admin-only, and say nothing about the org", mode_reviewed: "2026-09-01", tag: "Code search" }
      - { method: "GET", path: "/api/v4/ai/duo_workflows/code_review/custom_instructions", area: "gitlab duo workflows", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has AgentSession but no Duo-shaped workflow, checkpoint or trace projection", mode_reviewed: "2026-09-01", tag: "GitLab Duo workflows", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/ai/duo_workflows/list_tools", area: "gitlab duo workflows", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has AgentSession but no Duo-shaped workflow, checkpoint or trace projection", mode_reviewed: "2026-09-01", tag: "GitLab Duo workflows", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/ai/duo_workflows/workflows/{id}", area: "gitlab duo workflows", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has AgentSession but no Duo-shaped workflow, checkpoint or trace projection", mode_reviewed: "2026-09-01", tag: "GitLab Duo workflows", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/ai/duo_workflows/workflows/{id}/checkpoints", area: "gitlab duo workflows", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has AgentSession but no Duo-shaped workflow, checkpoint or trace projection", mode_reviewed: "2026-09-01", tag: "GitLab Duo workflows", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/ai/duo_workflows/workflows/{id}/checkpoints/{checkpoint_id}", area: "gitlab duo workflows", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has AgentSession but no Duo-shaped workflow, checkpoint or trace projection", mode_reviewed: "2026-09-01", tag: "GitLab Duo workflows", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/ai/duo_workflows/workflows/{id}/events", area: "gitlab duo workflows", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has AgentSession but no Duo-shaped workflow, checkpoint or trace projection", mode_reviewed: "2026-09-01", tag: "GitLab Duo workflows", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/ai/duo_workflows/workflows/{workflow_id}/trace.jsonl", area: "gitlab duo workflows", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has AgentSession but no Duo-shaped workflow, checkpoint or trace projection", mode_reviewed: "2026-09-01", tag: "GitLab Duo workflows", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/ai/duo_workflows/workflows/agent_privileges", area: "gitlab duo workflows", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has AgentSession but no Duo-shaped workflow, checkpoint or trace projection", mode_reviewed: "2026-09-01", tag: "GitLab Duo workflows", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/ai/duo_workflows/ws", area: "gitlab duo workflows", tier: 3, status: "deferred", mode: "refuse", mode_reason: "a WebSocket upgrade is not an HTTP read and the gateway serves no bidirectional channel", mode_reviewed: "2026-09-01", tag: "GitLab Duo workflows", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/analytics/code_review", area: "code review analytics", tier: 3, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W8): GitLab's own definition of the review queue, in its own words — the OPEN merge requests that have at least one non-author comment, ordered by review time with the longest first. reader.listPulls + pullReviewComments + listReviews; a merge request nobody has reviewed is absent rather than listed with a null time, which is what makes the queue a queue. `review_time` is whole hours from the first non-author note to the NEWEST INSTANT this universe records against that merge request (`mrUpdatedEpoch`, the same value `updated_at` publishes, widened by the conversation's own last note and last review): a snapshot has a last recorded event rather than a wall clock, canon carries review comments that postdate the anchor, and anchoring the subtraction would print a negative duration for a merge request that is plainly under review. `approved_by` is the approving reviews' authors and is a `deviation`, the vendored component typing a collection as one object. `diff_stats` is OMITTED: canon's `pull` carries no line counts at all and inventing them would be a placeholder", mode_reviewed: "2026-09-12", tag: "Code review analytics", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/analytics/group_activity/issues_count", area: "analytics", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W8): `Gitlab::Analytics::GroupActivityCalculator`'s own fold — what was created in the last 90 days, capped at its own RECENT_COUNT_LIMIT of 1000. THE CLOCK IS THE ARTIFACT'S ANCHOR, never Date.now(): the operation's window is relative to \"now\", and a replica that read the wall clock would answer differently on every request and differently again on a frozen pin a year from now. `group_path` is a REQUIRED parameter and resolves the container the same way `/api/v4/groups/{id}` resolves an id, so both containers this host lists answer and a path nobody has is GitLab's own 404 rather than a count of nothing. The count is over reader.listIssues(repo) across every repository the container owns; conformance recomputes it from the artifact rather than asserting a constant", mode_reviewed: "2026-09-12", tag: "Analytics", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/analytics/group_activity/merge_requests_count", area: "analytics", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W8): `Gitlab::Analytics::GroupActivityCalculator`'s own fold — what was created in the last 90 days, capped at its own RECENT_COUNT_LIMIT of 1000. THE CLOCK IS THE ARTIFACT'S ANCHOR, never Date.now(): the operation's window is relative to \"now\", and a replica that read the wall clock would answer differently on every request and differently again on a frozen pin a year from now. `group_path` is a REQUIRED parameter and resolves the container the same way `/api/v4/groups/{id}` resolves an id, so both containers this host lists answer and a path nobody has is GitLab's own 404 rather than a count of nothing. The count is over reader.listPulls(repo) across every repository the container owns; conformance recomputes it from the artifact rather than asserting a constant", mode_reviewed: "2026-09-12", tag: "Analytics", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/analytics/group_activity/new_members_count", area: "analytics", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W8): `Gitlab::Analytics::GroupActivityCalculator`'s own fold — what was created in the last 90 days, capped at its own RECENT_COUNT_LIMIT of 1000. THE CLOCK IS THE ARTIFACT'S ANCHOR, never Date.now(): the operation's window is relative to \"now\", and a replica that read the wall clock would answer differently on every request and differently again on a frozen pin a year from now. `group_path` is a REQUIRED parameter and resolves the container the same way `/api/v4/groups/{id}` resolves an id, so both containers this host lists answer and a path nobody has is GitLab's own 404 rather than a count of nothing. The one count that needs a JOIN DATE, which is why it alone of the three is generation-gated: `membership.added_epoch` ships with hello-16's access domain, and on an older artifact the row answers the membership generation gap rather than 0 — a zero would say nobody joined this group in the window, and an artifact carrying no membership row says nothing at all about when anybody joined. An invitation nobody accepted is NOT a member, so the pending rows are excluded exactly as `/groups/{id}/members` excludes them, which conformance asserts", mode_reviewed: "2026-09-12", tag: "Analytics", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/application/appearance", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Instance", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/application/plan_limits", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Plan limits", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/application/settings", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Instance", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/application/statistics", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Instance", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/applications", area: "applications", tier: 3, status: "deferred", mode: "refuse", mode_reason: "application registration is a control-plane surface of the vendor's auth system; SandboxAPIs issues its own keys and the instance list is admin-only", mode_reviewed: "2026-09-01", tag: "Applications", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/audit_events", area: "audit-events", tier: 3, status: "deferred", mode: "generate", mode_reason: "A WIDENING, NOT A BUILD: canon.AdminAuditEvent exists (packages/canon/src/support-desk.ts:690) and its own doc comment calls it \"GENERIC by construction\". The action vocabulary (AuditAction, :602), the change vocabulary (AuditChangeSlot, :633), the target vocabulary (AuditTargetKind, :611) and the RFC 5737 source-address rule (AuditSourceBlock, :652) all shipped, and Zendesk serves the table today (reader.listAuditEvents(), ruled 2026-09-07). TWO things are missing and neither is the entity: git-host members on AuditTargetKind, and a generation that WRITES personActor — the field is declared for exactly this wave and \"this generation writes none\" (:695-697)", mode_reviewed: "2026-09-09", tag: "Audit events" }
      - { method: "GET", path: "/api/v4/audit_events/{id}", area: "audit-events", tier: 3, status: "deferred", mode: "generate", mode_reason: "A WIDENING, NOT A BUILD: canon.AdminAuditEvent exists (packages/canon/src/support-desk.ts:690) and its own doc comment calls it \"GENERIC by construction\". The action vocabulary (AuditAction, :602), the change vocabulary (AuditChangeSlot, :633), the target vocabulary (AuditTargetKind, :611) and the RFC 5737 source-address rule (AuditSourceBlock, :652) all shipped, and Zendesk serves the table today (reader.listAuditEvents(), ruled 2026-09-07). TWO things are missing and neither is the entity: git-host members on AuditTargetKind, and a generation that WRITES personActor — the field is declared for exactly this wave and \"this generation writes none\" (:695-697)", mode_reviewed: "2026-09-09", tag: "Audit events" }
      - { method: "GET", path: "/api/v4/avatar", area: "avatars", tier: 3, status: "green", mode: "derive", mode_reason: "THE OLD REASON WAS WRONG (DECISIONS 2026-09-06 [HELLO-15/avatars-reactions] finding a): the vendored spec's own summary is \"Return avatar url for a user\" and its one required parameter is email. It is a PERSON lookup, not an Attachment - PersonAvatar (hello-13) plus the org-wide login@{org}.dev convention every host joins on answer it. An address naming nobody gets avatar_url null, which is real GitLab with Gravatar disabled; a @users.noreply address deliberately does not resolve, because real GitLab looks up the PUBLIC email", mode_reviewed: "2026-09-07", tag: "Avatars", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/broadcast_messages", area: "instance-admin", tier: 3, status: "green", mode: "empty", mode_reason: "no broadcast message has ever been posted on this instance: a broadcast exists only because an admin created one, and this universe has no admin acting on it", mode_reviewed: "2026-09-01", tag: "Broadcast messages", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/broadcast_messages/{id}", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the collection this id would index is empty in this universe, so the only honest answer is the vendor's own 404", mode_reviewed: "2026-09-01", tag: "Broadcast messages", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/bulk_imports", area: "imports", tier: 3, status: "deferred", mode: "refuse", mode_reason: "each of these reads reports on an export or import that a WRITE would have started, and writes are refused; GitLab answers 404 for an export nobody requested", mode_reviewed: "2026-09-01", tag: "Imports", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/bulk_imports/{import_id}", area: "imports", tier: 3, status: "deferred", mode: "refuse", mode_reason: "each of these reads reports on an export or import that a WRITE would have started, and writes are refused; GitLab answers 404 for an export nobody requested", mode_reviewed: "2026-09-01", tag: "Imports", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/bulk_imports/{import_id}/entities", area: "imports", tier: 3, status: "deferred", mode: "refuse", mode_reason: "each of these reads reports on an export or import that a WRITE would have started, and writes are refused; GitLab answers 404 for an export nobody requested", mode_reviewed: "2026-09-01", tag: "Imports", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/bulk_imports/{import_id}/entities/{entity_id}", area: "imports", tier: 3, status: "deferred", mode: "refuse", mode_reason: "each of these reads reports on an export or import that a WRITE would have started, and writes are refused; GitLab answers 404 for an export nobody requested", mode_reviewed: "2026-09-01", tag: "Imports", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/bulk_imports/{import_id}/entities/{entity_id}/failures", area: "imports", tier: 3, status: "deferred", mode: "refuse", mode_reason: "each of these reads reports on an export or import that a WRITE would have started, and writes are refused; GitLab answers 404 for an export nobody requested", mode_reviewed: "2026-09-01", tag: "Imports", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/bulk_imports/entities", area: "imports", tier: 3, status: "deferred", mode: "refuse", mode_reason: "each of these reads reports on an export or import that a WRITE would have started, and writes are refused; GitLab answers 404 for an export nobody requested", mode_reviewed: "2026-09-01", tag: "Imports", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/databases/{database_name}/dictionary/tables", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Database dictionary", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/dependency_list_exports/{export_id}", area: "dependency management", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the export object can only be created by a POST we refuse, so the by-id read can only ever be the vendor's own 404", mode_reviewed: "2026-09-01", tag: "Dependency management", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/dependency_list_exports/{export_id}/download", area: "dependency management", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the export object can only be created by a POST we refuse, so the by-id read can only ever be the vendor's own 404", mode_reviewed: "2026-09-01", tag: "Dependency management", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/deploy_keys", area: "deploy-keys-tokens", tier: 3, status: "deferred", mode: "refuse", mode_reason: "listing every key, deploy token or impersonation token across the instance requires admin on GitLab; answering would be inventing an admin session", mode_reviewed: "2026-09-01", tag: "Deploy resources" }
      - { method: "GET", path: "/api/v4/deploy_tokens", area: "deploy-keys-tokens", tier: 3, status: "deferred", mode: "refuse", mode_reason: "listing every key, deploy token or impersonation token across the instance requires admin on GitLab; answering would be inventing an admin session", mode_reviewed: "2026-09-01", tag: "Deploy resources" }
      - { method: "GET", path: "/api/v4/discover-cert-based-clusters", area: "clusters", tier: 3, status: "deferred", mode: "refuse", mode_reason: "certificate-based cluster integration is disabled on GitLab.com and removed upstream; mirroring it would advertise a surface no current client can reach", mode_reviewed: "2026-09-01", tag: "Clusters", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/events", area: "events", tier: 2, status: "green", mode: "derive", tag: "Events" }
      - { method: "GET", path: "/api/v4/experiments", area: "experiments", tier: 3, status: "deferred", mode: "refuse", mode_reason: "these report GitLab Inc.'s own A/B assignments for the caller, are admin-only, and describe the vendor rather than the org", mode_reviewed: "2026-09-01", tag: "Experiments", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/experiments/{experiment_name}/assignments", area: "experiments", tier: 3, status: "deferred", mode: "refuse", mode_reason: "these report GitLab Inc.'s own A/B assignments for the caller, are admin-only, and describe the vendor rather than the org", mode_reviewed: "2026-09-01", tag: "Experiments", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/feature_flags/unleash/{project_id}", area: "unleash", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no FeatureFlag; a shipping org gates releases behind flags", mode_reviewed: "2026-09-01", tag: "Unleash", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/feature_flags/unleash/{project_id}/client/features", area: "unleash", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no FeatureFlag; a shipping org gates releases behind flags", mode_reviewed: "2026-09-01", tag: "Unleash", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/feature_flags/unleash/{project_id}/features", area: "unleash", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no FeatureFlag; a shipping org gates releases behind flags", mode_reviewed: "2026-09-01", tag: "Unleash", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/features", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Features", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/features/definitions", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Features", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/geo_nodes", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Geo", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/geo_nodes/{id}", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Geo", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/geo_nodes/{id}/status", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Geo", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/geo_nodes/status", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Geo", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/geo_sites", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Geo", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/geo_sites/{id}", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Geo", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/geo_sites/{id}/status", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Geo", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/geo_sites/status", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Geo", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/geo/proxy", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Geo", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/geo/repositories/{gl_repository}/pipeline_refs", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Geo", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/geo/retrieve/{replicable_name}/{replicable_id}", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Geo", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/group_repository_storage_moves", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Storage moves", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/group_repository_storage_moves/{repository_storage_move_id}", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Storage moves", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/group/{id}/-/packages/composer/p/{sha}", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Composer" }
      - { method: "GET", path: "/api/v4/group/{id}/-/packages/composer/packages", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Composer" }
      - { method: "GET", path: "/api/v4/groups", area: "groups", tier: 1, status: "green", mode: "derive", tag: "Groups" }
      - { method: "GET", path: "/api/v4/groups/{id}", area: "groups", tier: 1, status: "green", mode: "derive", tag: "Groups" }
      - { method: "GET", path: "/api/v4/groups/{id}/-/debian_distributions", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Debian" }
      - { method: "GET", path: "/api/v4/groups/{id}/-/debian_distributions/{codename}", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Debian" }
      - { method: "GET", path: "/api/v4/groups/{id}/-/debian_distributions/{codename}/key.asc", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Debian" }
      - { method: "GET", path: "/api/v4/groups/{id}/-/epics", area: "epics", tier: 2, status: "deviation", mode: "derive", mode_reason: "EpicRow carries the portfolio columns from hello-16 (features.portfolio): author, state, description, start/due/closed epochs and one level of parent/child. reader.hasPortfolio() + listEpics()/epic()/epicChildren()/epicIssues() derive GitLab's Epic entity; older pins answer the noEpics generation-gap 404 rather than an empty plan. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", tag: "Epics" }
      - { method: "GET", path: "/api/v4/groups/{id}/-/epics/{epic_iid}", area: "epics", tier: 2, status: "deviation", mode: "derive", mode_reason: "EpicRow carries the portfolio columns from hello-16 (features.portfolio): author, state, description, start/due/closed epochs and one level of parent/child. reader.hasPortfolio() + listEpics()/epic()/epicChildren()/epicIssues() derive GitLab's Epic entity; older pins answer the noEpics generation-gap 404 rather than an empty plan. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", tag: "Epics" }
      - { method: "GET", path: "/api/v4/groups/{id}/-/epics/{epic_iid}/issues", area: "epics", tier: 2, status: "deviation", mode: "derive", mode_reason: "EpicRow carries the portfolio columns from hello-16 (features.portfolio): author, state, description, start/due/closed epochs and one level of parent/child. reader.hasPortfolio() + listEpics()/epic()/epicChildren()/epicIssues() derive GitLab's Epic entity; older pins answer the noEpics generation-gap 404 rather than an empty plan. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", tag: "Epics" }
      - { method: "GET", path: "/api/v4/groups/{id}/-/packages/debian/pool/{distribution}/{project_id}/{letter}/{package_name}/{package_version}/{file_name}", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Debian" }
      - { method: "GET", path: "/api/v4/groups/{id}/-/packages/nuget/index", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: NuGet" }
      - { method: "GET", path: "/api/v4/groups/{id}/-/packages/nuget/query", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: NuGet" }
      - { method: "GET", path: "/api/v4/groups/{id}/-/packages/nuget/v2", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: NuGet" }
      - { method: "GET", path: "/api/v4/groups/{id}/-/packages/nuget/v2/$metadata", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: NuGet" }
      - { method: "GET", path: "/api/v4/groups/{id}/-/packages/pypi/simple", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: PyPi" }
      - { method: "GET", path: "/api/v4/groups/{id}/(-/)epics/{epic_iid}/epics", area: "epics", tier: 2, status: "deviation", mode: "derive", mode_reason: "the CHILD epics of an epic - GitLab's Epics::EpicLinks, which the vendored summary labels \"related epics\" while its POST twin says \"relate epic to a PARENT\". epic.parent/level are canon from hello-16 (features.portfolio) and reader.epicChildren(id) answers it directly; a leaf reports the empty array and an older pin the noEpics generation-gap 404. The 2026-09-01 reason was right that parentage was not modelled and is no longer true; the SIBLING relation it also names still is not, which is why groups/{id}/epics/{epic_iid}/related_epics stays generate. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", tag: "Epics" }
      - { method: "GET", path: "/api/v4/groups/{id}/(-/)search", area: "search", tier: 2, status: "deviation", mode: "derive", mode_reason: "scope-dispatched search over the group's projects. THE SUBGROUP RESOLVES HERE as of 2026-09-10 and answers the empty result set for every scope, because a group search is a search over its PROJECTS and it owns none (founder ruling F1). A missing or invalid `scope` is still GitLab's own 400 on either id", mode_reviewed: "2026-09-10", tag: "Search" }
      - { method: "GET", path: "/api/v4/groups/{id}/access_requests", area: "access requests", tier: 3, status: "green", mode: "empty", mode_reason: "membership here is granted directly by the group's own scaffolding; nobody has ever REQUESTED access, so the pending-request list is truthfully empty. THE SUBGROUP RESOLVES HERE as of 2026-09-10 and answers the SAME empty list: an access request is an ACTION this canon records none of, which is a fact about the universe rather than about one container", mode_reviewed: "2026-09-10", tag: "Access requests", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/access_tokens", area: "deploy-keys-tokens", tier: 3, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-10 (hello-16): reader.listCredentials(\"group-token\") filtered on scope_ref (reader.ts:3085) — one row, the roster-sync token scoped to the organization's own group. THE SUBGROUP RESOLVES AND ANSWERS []: it owns no repository and has no automation to run (founder ruling F1, 2026-09-09), and conformance drives both ids. `access_level` is the holder's own organization standing, the same derivation the project rows use. Unpaginated, per the vendored operation. Gated on hasCredentials()", mode_reviewed: "2026-09-10", tag: "Access tokens" }
      - { method: "GET", path: "/api/v4/groups/{id}/access_tokens/{token_id}", area: "deploy-keys-tokens", tier: 3, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-10 (hello-16): the same row by id, byte-identical to the list's first entry. The organization's token id does NOT resolve under the subgroup — conformance asserts it, because a token belongs to one group rather than to every group on the host", mode_reviewed: "2026-09-10", tag: "Access tokens" }
      - { method: "GET", path: "/api/v4/groups/{id}/approval_rules", area: "merge-requests", tier: 1, status: "green", mode: "empty", mode_reason: "SERVED 2026-09-12 (hello-17): an HONEST EMPTY, and gated. features.reviewPolicy exists and the route QUERIES the container's own id against scope_kind/scope rather than hard-coding [] - so it serves a namespace-scoped rule the day canon writes one. None exists: a rule is measured off the merges in its scope, the organization's merges all happen in its one project, and the subgroup owns no repository (founder ruling F1), so neither group id has a rule of its own. On every artifact without the domain the route answers the named hello-17 generation gap instead, because [] there would assert that nothing gates a merge in an organization whose every merge carried reviews", mode_reviewed: "2026-09-12", tag: "Approval rules" }
      - { method: "GET", path: "/api/v4/groups/{id}/audit_events", area: "audit-events", tier: 3, status: "deferred", mode: "generate", mode_reason: "A WIDENING, NOT A BUILD: canon.AdminAuditEvent exists (packages/canon/src/support-desk.ts:690) and its own doc comment calls it \"GENERIC by construction\". The action vocabulary (AuditAction, :602), the change vocabulary (AuditChangeSlot, :633), the target vocabulary (AuditTargetKind, :611) and the RFC 5737 source-address rule (AuditSourceBlock, :652) all shipped, and Zendesk serves the table today (reader.listAuditEvents(), ruled 2026-09-07). TWO things are missing and neither is the entity: git-host members on AuditTargetKind, and a generation that WRITES personActor — the field is declared for exactly this wave and \"this generation writes none\" (:695-697)", mode_reviewed: "2026-09-09", tag: "Audit events" }
      - { method: "GET", path: "/api/v4/groups/{id}/audit_events/{audit_event_id}", area: "groups", tier: 1, status: "planned", mode: "generate", mode_reason: "A WIDENING, NOT A BUILD: canon.AdminAuditEvent exists (packages/canon/src/support-desk.ts:690) and its own doc comment calls it \"GENERIC by construction\". The action vocabulary (AuditAction, :602), the change vocabulary (AuditChangeSlot, :633), the target vocabulary (AuditTargetKind, :611) and the RFC 5737 source-address rule (AuditSourceBlock, :652) all shipped, and Zendesk serves the table today (reader.listAuditEvents(), ruled 2026-09-07). TWO things are missing and neither is the entity: git-host members on AuditTargetKind, and a generation that WRITES personActor — the field is declared for exactly this wave and \"this generation writes none\" (:695-697)", mode_reviewed: "2026-09-09", tag: "Groups" }
      - { method: "GET", path: "/api/v4/groups/{id}/avatar", area: "avatars", tier: 3, status: "green", mode: "derive", mode_reason: "the group's own identicon bytes from reader.orgAvatar(\"org\", org) — one picture per container across every host that serves one. THE SUBGROUP RESOLVES HERE as of 2026-09-10 and answers `404 Avatar Not Found`, GitLab's own answer for a group nobody uploaded an avatar for: `org_avatar` is keyed `org` and `repo` and no row names a namespace, which is also why glSubgroup prints no avatar_url for it. Older pins still answer the noOrgAvatars generation gap", mode_reviewed: "2026-09-10", tag: "Avatars", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/badges", area: "badges", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Badge; project READMEs in this universe carry pipeline and coverage badges", mode_reviewed: "2026-09-01", tag: "Badges", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/badges/{badge_id}", area: "badges", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Badge; project READMEs in this universe carry pipeline and coverage badges", mode_reviewed: "2026-09-01", tag: "Badges", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/badges/render", area: "badges", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Badge; project READMEs in this universe carry pipeline and coverage badges", mode_reviewed: "2026-09-01", tag: "Badges", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/billable_members", area: "groups", tier: 1, status: "green", mode: "derive", mode_reason: "every member counts against the seats: canon models no guest, no minimal access and no service account, so nobody here holds a membership without occupying one. THE SUBGROUP RESOLVES HERE as of 2026-09-10 AND ANSWERS GITLAB'S OWN 404: the vendored document says this lists billable members \"of a specified TOP-LEVEL group\", so the operation does not exist for a subgroup — a different fact from having no billable member, and a `200 []` would report the second while the provider reports the first", mode_reviewed: "2026-09-10", tag: "Groups" }
      - { method: "GET", path: "/api/v4/groups/{id}/billable_members/{user_id}/indirect", area: "groups", tier: 1, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): WAS `empty` AND THE RULING WAS FALSIFIED ON SCHEDULE. The 2026-09-09 namespaces decision said in as many words that the day canon gives a namespace a member this goes red rather than hiding it; features.grants gives the subgroup a roster of five - the people whose authority is over the PLAN rather than over the code - so this route serves that person's namespace membership, with created_at read off the membership row's own instant rather than the person's first sighting. A person on no namespace roster still gets [], which is what keeps this a derive rather than a claim that everybody is in the subgroup. THE SUBGROUP STILL ANSWERS GITLAB'S OWN 404: the vendored document says the operation works on top-level groups only. On every artifact without the domain namespaceMembers() finds nothing and the answer is the [] all 127 registered pins serve", mode_reviewed: "2026-09-12", tag: "Members" }
      - { method: "GET", path: "/api/v4/groups/{id}/billable_members/{user_id}/memberships", area: "groups", tier: 1, status: "deviation", mode: "derive", mode_reason: "the memberships that put one person on a seat: the group, then every project it owns — the same two levels /users/{id}/memberships reports. THE SUBGROUP RESOLVES HERE as of 2026-09-10 and answers GitLab's 404, with the rest of the billable-members family: it addresses a billable member OF a group whose own billable list does not exist for a subgroup, and a member of a list that 404s cannot resolve (invariant #5 from the other end)", mode_reviewed: "2026-09-10", tag: "Members" }
      - { method: "GET", path: "/api/v4/groups/{id}/boards", area: "boards", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has sprint/epic/workflow state but no Board; the board layout itself must be generated", mode_reviewed: "2026-09-01", tag: "Boards", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/boards/{board_id}", area: "boards", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has sprint/epic/workflow state but no Board; the board layout itself must be generated", mode_reviewed: "2026-09-01", tag: "Boards", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/boards/{board_id}/lists", area: "boards", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has sprint/epic/workflow state but no Board; the board layout itself must be generated", mode_reviewed: "2026-09-01", tag: "Boards", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/boards/{board_id}/lists/{list_id}", area: "boards", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has sprint/epic/workflow state but no Board; the board layout itself must be generated", mode_reviewed: "2026-09-01", tag: "Boards", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/clusters", area: "clusters", tier: 3, status: "deferred", mode: "refuse", mode_reason: "certificate-based cluster integration is disabled on GitLab.com and removed upstream; mirroring it would advertise a surface no current client can reach", mode_reviewed: "2026-09-01", tag: "Clusters", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/clusters/{cluster_id}", area: "clusters", tier: 3, status: "deferred", mode: "refuse", mode_reason: "certificate-based cluster integration is disabled on GitLab.com and removed upstream; mirroring it would advertise a surface no current client can reach", mode_reviewed: "2026-09-01", tag: "Clusters", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/custom_attributes", area: "custom attributes", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab restricts custom attributes to instance administrators; a non-admin token gets 403", mode_reviewed: "2026-09-01", tag: "Custom attributes", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/custom_attributes/{key}", area: "custom attributes", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab restricts custom attributes to instance administrators; a non-admin token gets 403", mode_reviewed: "2026-09-01", tag: "Custom attributes", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/deploy_tokens", area: "deploy-keys-tokens", tier: 3, status: "green", mode: "empty", mode_reason: "this organization's one deploy token is scoped to its one REPOSITORY, which is where a registry-pull token belongs: reader.listCredentials(\"deploy-token\") (reader.ts:3085) holds one row and its scope_ref is a RepoId, so the GROUP-level list is truthfully empty while /api/v4/projects/{id}/deploy_tokens serves that row. SERVED 2026-09-10 as GitLab's empty page with the pagination headers the vendored operation's page/per_page declare, behind the hello-16 credential gate — an older artifact answers the named generation gap, not []. The subgroup resolves here and is empty for a second reason: it owns no repository and so has no registry to pull (founder ruling F1). RULED by the founder 2026-09-10", mode_reviewed: "2026-09-10", tag: "Deploy resources" }
      - { method: "GET", path: "/api/v4/groups/{id}/deploy_tokens/{token_id}", area: "deploy-keys-tokens", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the by-id twin of the group deploy-token list: that list is truthfully empty, so no id can resolve and GitLab's own 404 is the whole answer rather than a coverage miss. SERVED 2026-09-10 with x-sandboxapis-refusal naming this row, and UNGATED unlike the list — no generation of this universe holds a group-level deploy token, so the 404 is true on every artifact and naming the credential generation gap here would point a caller at a live host that answers the identical 404. The group still has to resolve: an id nobody holds is 404 Group Not Found, and the subgroup gets this same refusal. RULED by the founder 2026-09-10", mode_reviewed: "2026-09-10", tag: "Deploy resources" }
      - { method: "GET", path: "/api/v4/groups/{id}/descendant_groups", area: "groups", tier: 1, status: "deviation", mode: "derive", mode_reason: "the transitive twin of the subgroup list, from the same reader.listNamespaces walk. One level deep in this universe, so it answers the same single row; older pins still answer the empty list. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", tag: "Groups" }
      - { method: "GET", path: "/api/v4/groups/{id}/dora/metrics", area: "dora metrics", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W8): the four DORA metrics folded over reader.listDeployments, listIncidents and pullsForCommit — no new fact, and a caller can recompute every value from `/projects/{id}/deployments` and `/projects/{id}/merge_requests`, which is exactly what conformance does. deployment_frequency counts the successful deployments in the requested environment tiers; lead_time_for_changes is the median of (deployment instant − merge instant) over the merge requests each deployment shipped, reached through the same pullsForCommit read `/deployments/{id}/merge_requests` serves so a lead time and that list cannot disagree; time_to_restore_service is the median of (resolved − opened) over the incidents whose canonical issue belongs to the scope; change_failure_rate is those incidents over those deployments. A MEDIAN OF NOTHING IS NULL, never a zero — a lead time of no time is a different claim from no measurement — while a COUNT of nothing is 0, and conformance drives a window with no deployment to hold that line. THE SHAPE IS PINNED HERE because the vendored document declares NO schema for the 200 at all (`\"200\": {\"description\": \"successful operation\"}` and nothing else): an entry per bucket, `{date, value}`, `date` being the bucket's first UTC day. THE CLOCK IS THE ANCHOR: `end_date` defaults to the artifact's own anchor day and `start_date` to 90 UTC days before it, the same window the group-activity counts use. The group folds every repository it owns. This universe has one, so the group series and the project series must AGREE — conformance compares them rather than leaving the coincidence implicit", mode_reviewed: "2026-09-12", tag: "DORA metrics", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/enterprise_users", area: "enterprise users", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-18): THE SAME SIXTEEN PEOPLE ANSWER saml_users, provisioned_users AND enterprise_users, and that is GitLab's own definition rather than a shortcut: an enterprise user is one the group provisioned through its own SAML/SCIM, and a SAML user and a provisioned user are that sentence read from the other two ends. canon carries ONE identity_provider_config (protocol saml, scim_enabled 1) and one external_uid per person, so the three lists are one set and conformance asserts they are identical rather than leaving it a coincidence. THE MACHINE ACCOUNT IS EXCLUDED and that is the domain's load-bearing ruling (decisions/2026-09-12-1120): canon writes no external_uid for the CI bot, because a directory provisions humans and GitLab's word for a machine principal is a SERVICE ACCOUNT — a different object, a different API family, and one five armed `…/service_accounts` rulings say this universe does not mint. The rows are glUser, byte-identical to what /api/v4/users/{id} serves for each of them, which conformance checks person by person. THE SUBGROUP GETS GITLAB'S OWN not_found!, on the vendored description's own words (\"for a specified top-level group\"). Gated on hasExternalUid(); an older artifact answers the named hello-18 identity gap rather than [], because an empty list there would say nobody here was provisioned by a directory while this same host publishes a SAML configuration with SCIM enabled — the replica disagreeing with itself (invariant #5)", mode_reviewed: "2026-09-12", tag: "Enterprise users", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/enterprise_users/{user_id}", area: "enterprise users", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-18): one enterprise user by numeric id, byte-identical to that person's entry in the list. A PERSON THE ROSTER HAS AND THE DIRECTORY DID NOT PROVISION IS GITLAB'S 404 HERE, not a 200, and that is the whole point of the endpoint: it answers who is an enterprise user rather than who exists. Conformance drives the CI bot's own id, asserts the 404, and asserts the same id DOES resolve at /api/v4/users/{id} — so the refusal is about the family rather than about an id nobody has. The subgroup gets GitLab's own not_found! with its list. Gated on hasExternalUid(); an older artifact answers the named hello-18 identity gap rather than [], because an empty list there would say nobody here was provisioned by a directory while this same host publishes a SAML configuration with SCIM enabled — the replica disagreeing with itself (invariant #5)", mode_reviewed: "2026-09-12", tag: "Enterprise users", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/epic_boards", area: "epics", tier: 2, status: "deferred", mode: "generate", mode_reason: "canon has sprint/epic/workflow state but no Board; the board layout itself must be generated", mode_reviewed: "2026-09-01", tag: "Epics" }
      - { method: "GET", path: "/api/v4/groups/{id}/epic_boards/{board_id}", area: "epics", tier: 2, status: "deferred", mode: "generate", mode_reason: "canon has sprint/epic/workflow state but no Board; the board layout itself must be generated", mode_reviewed: "2026-09-01", tag: "Epics" }
      - { method: "GET", path: "/api/v4/groups/{id}/epic_boards/{board_id}/lists", area: "epics", tier: 2, status: "deferred", mode: "generate", mode_reason: "canon has sprint/epic/workflow state but no Board; the board layout itself must be generated", mode_reviewed: "2026-09-01", tag: "Epics" }
      - { method: "GET", path: "/api/v4/groups/{id}/epic_boards/{board_id}/lists/{list_id}", area: "epics", tier: 2, status: "deferred", mode: "generate", mode_reason: "canon has sprint/epic/workflow state but no Board; the board layout itself must be generated", mode_reviewed: "2026-09-01", tag: "Epics" }
      - { method: "GET", path: "/api/v4/groups/{id}/epics", area: "epics", tier: 2, status: "deviation", mode: "derive", mode_reason: "EpicRow carries the portfolio columns from hello-16 (features.portfolio): author, state, description, start/due/closed epochs and one level of parent/child. reader.hasPortfolio() + listEpics()/epic()/epicChildren()/epicIssues() derive GitLab's Epic entity; older pins answer the noEpics generation-gap 404 rather than an empty plan. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", tag: "Epics" }
      - { method: "GET", path: "/api/v4/groups/{id}/epics/{epic_iid}", area: "epics", tier: 2, status: "deviation", mode: "derive", mode_reason: "EpicRow carries the portfolio columns from hello-16 (features.portfolio): author, state, description, start/due/closed epochs and one level of parent/child. reader.hasPortfolio() + listEpics()/epic()/epicChildren()/epicIssues() derive GitLab's Epic entity; older pins answer the noEpics generation-gap 404 rather than an empty plan. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", tag: "Epics" }
      - { method: "GET", path: "/api/v4/groups/{id}/epics/{epic_iid}/award_emoji", area: "award emoji", tier: 3, status: "green", mode: "derive", mode_reason: "content_reaction has carried target_kind 'epic' since hello-15; the block was that this renderer served no epic route, and hello-16's portfolio layer gives the epic one. reactionsFor('epic', id) under a resolvable epic_iid. Two gates in the order a caller meets them: no epic before hello-16 (noEpics), no reactions before hello-15 (noAwardEmoji). SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", tag: "Award emoji", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/epics/{epic_iid}/award_emoji/{award_id}", area: "award emoji", tier: 3, status: "green", mode: "derive", mode_reason: "content_reaction has carried target_kind 'epic' since hello-15; the block was that this renderer served no epic route, and hello-16's portfolio layer gives the epic one. reactionsFor('epic', id) under a resolvable epic_iid. Two gates in the order a caller meets them: no epic before hello-16 (noEpics), no reactions before hello-15 (noAwardEmoji). SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", tag: "Award emoji", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/epics/{epic_iid}/issues", area: "epics", tier: 2, status: "deviation", mode: "derive", mode_reason: "EpicRow carries the portfolio columns from hello-16 (features.portfolio): author, state, description, start/due/closed epochs and one level of parent/child. reader.hasPortfolio() + listEpics()/epic()/epicChildren()/epicIssues() derive GitLab's Epic entity; older pins answer the noEpics generation-gap 404 rather than an empty plan. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", tag: "Epics" }
      - { method: "GET", path: "/api/v4/groups/{id}/epics/{epic_iid}/notes/{note_id}/award_emoji", area: "award emoji", tier: 3, status: "deferred", mode: "generate", mode_reason: "HALF UNBLOCKED 2026-09-12 (hello-17): the epic-COMMENT entity this reason used to name EXISTS now (features.entityNotes) and this renderer serves all six epic note and discussion routes, so a note_id resolves. What is still missing is the AWARDABLE: content_reaction carries target_kind values for issues, comments, pulls, review comments, releases and epics, and nothing in the reaction pass attaches a reaction to an epic NOTE. [] here would assert that nobody reacted to this sentence, which is a claim about the people rather than about the artifact, so the row keeps the coverage 404. THE ASK: an `entityNote` awardable kind in the reaction pass, and this row plus its by-id twin go green with no new entity", mode_reviewed: "2026-09-12", tag: "Award emoji", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/epics/{epic_iid}/notes/{note_id}/award_emoji/{award_id}", area: "award emoji", tier: 3, status: "deferred", mode: "generate", mode_reason: "HALF UNBLOCKED 2026-09-12 (hello-17): the by-id twin of the epic-note award list, and blocked by the same single fact - the note exists and resolves as of this wave, the reaction on it does not, because no content_reaction row carries an epic note as its target. THE ASK is the list row's", mode_reviewed: "2026-09-12", tag: "Award emoji", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/epics/{epic_iid}/related_epics", area: "epics", tier: 2, status: "deferred", mode: "generate", mode_reason: "STILL BLOCKED 2026-09-12 (hello-17): IssueLink is canon now and the four issue-to-issue rows serve, but this operation is EPIC-to-EPIC and issue_link's source and target are both issue ids. The one epic relation canon carries is PARENTAGE (features.portfolio's level and parent), which GitLab serves at /epics/{epic_iid}/epics and is a different relation from the sibling `related_epics` set. THE ASK: an epic-to-epic link kind, or a widening of issue_link's ends to a discriminated parent", mode_reviewed: "2026-09-12", tag: "Epics" }
      - { method: "GET", path: "/api/v4/groups/{id}/epics/{eventable_id}/resource_label_events", area: "events", tier: 2, status: "deferred", mode: "generate", mode_reason: "canon keeps current label/milestone state, not its history; needs a ResourceEvent log", mode_reviewed: "2026-09-01", tag: "Resource events" }
      - { method: "GET", path: "/api/v4/groups/{id}/epics/{eventable_id}/resource_label_events/{event_id}", area: "events", tier: 2, status: "deferred", mode: "generate", mode_reason: "canon keeps current label/milestone state, not its history; needs a ResourceEvent log", mode_reviewed: "2026-09-01", tag: "Resource events" }
      - { method: "GET", path: "/api/v4/groups/{id}/epics/{eventable_id}/resource_state_events", area: "events", tier: 2, status: "deferred", mode: "generate", mode_reason: "canon keeps current label/milestone state, not its history; needs a ResourceEvent log", mode_reviewed: "2026-09-01", tag: "Resource events" }
      - { method: "GET", path: "/api/v4/groups/{id}/epics/{eventable_id}/resource_state_events/{event_id}", area: "events", tier: 2, status: "deferred", mode: "generate", mode_reason: "canon keeps current label/milestone state, not its history; needs a ResourceEvent log", mode_reviewed: "2026-09-01", tag: "Resource events" }
      - { method: "GET", path: "/api/v4/groups/{id}/epics/{noteable_id}/discussions", area: "discussions", tier: 1, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): a discussion IS the epic's notes grouped by entity_note.thread_root - not a second entity and not a second query - so /notes and /discussions partition exactly the same set and render each note identically. individual_note is `this thread has one note`; resolvable is false because GitLab makes only DIFF notes resolvable and an epic has no diff. The vendored component types `notes` as a single object where real GitLab sends an array, so the row is a deviation, exactly as its issue and merge-request twins are", mode_reviewed: "2026-09-12", tag: "Discussions" }
      - { method: "GET", path: "/api/v4/groups/{id}/epics/{noteable_id}/discussions/{discussion_id}", area: "discussions", tier: 1, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): one epic discussion by its 40-hex digest, which is SHA-1 over the canonical id of the thread's root note - the same derivation the issue and merge-request discussions use, so a discussion is addressable by exactly one thread. A discussion that belongs to a different epic 404s here rather than being served under the wrong parent", mode_reviewed: "2026-09-12", tag: "Discussions" }
      - { method: "GET", path: "/api/v4/groups/{id}/epics/{noteable_id}/discussions/{discussion_id}/notes", area: "discussions", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): the notes inside one epic discussion, byte-identical to the same notes inside the discussion object. The vendored document types this operation's 200 as APIEntitiesDiscussion - Grape's desc block disagreeing with a route that presents the NOTE collection - so conformance validates against APIEntitiesNote, which is what a client receives; the issue and merge-request twins make the same call", mode_reviewed: "2026-09-12", tag: "Discussions" }
      - { method: "GET", path: "/api/v4/groups/{id}/epics/{noteable_id}/discussions/{discussion_id}/notes/{note_id}", area: "discussions", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): one note inside one epic discussion, rendered by the same glEpicNote every other note surface uses", mode_reviewed: "2026-09-12", tag: "Discussions" }
      - { method: "GET", path: "/api/v4/groups/{id}/epics/{noteable_id}/notes", area: "notes", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): features.entityNotes gives a plan item the planning conversation the storyline already had - entity_note rows keyed to an epic, authored by the people who commented on the issues underneath it. listEntityNotes() answers this list in canon id order, which is chronological within a parent. On every older artifact it answers the named hello-17 generation gap and never [], because an empty note list asserts that this organization plans in silence", mode_reviewed: "2026-09-12", tag: "Notes" }
      - { method: "GET", path: "/api/v4/groups/{id}/epics/{noteable_id}/notes/{note_id}", area: "notes", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): one epic note by id, rendered by the same glEpicNote the list and the discussions use, so the three surfaces cannot describe one sentence three ways", mode_reviewed: "2026-09-12", tag: "Notes" }
      - { method: "GET", path: "/api/v4/groups/{id}/export_relations/download", area: "group import and export", tier: 3, status: "deferred", mode: "refuse", mode_reason: "each of these reads reports on an export or import that a WRITE would have started, and writes are refused; GitLab answers 404 for an export nobody requested", mode_reviewed: "2026-09-01", tag: "Group import and export", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/export_relations/status", area: "group import and export", tier: 3, status: "deferred", mode: "refuse", mode_reason: "each of these reads reports on an export or import that a WRITE would have started, and writes are refused; GitLab answers 404 for an export nobody requested", mode_reviewed: "2026-09-01", tag: "Group import and export", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/export/download", area: "group import and export", tier: 3, status: "deferred", mode: "refuse", mode_reason: "each of these reads reports on an export or import that a WRITE would have started, and writes are refused; GitLab answers 404 for an export nobody requested", mode_reviewed: "2026-09-01", tag: "Group import and export", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/groups/shared", area: "groups", tier: 1, status: "green", mode: "empty", mode_reason: "there IS a second group as of hello-16 and this is still empty, because a SHARE is an action and canon records none: no group here has ever been shared with another. THE SUBGROUP RESOLVES HERE as of 2026-09-10 and answers the same empty list, for the same reason", mode_reviewed: "2026-09-10", tag: "Groups" }
      - { method: "GET", path: "/api/v4/groups/{id}/hooks", area: "hooks-config", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-18): the hooks a group publishes to, off reader.orgWebhooks for the organization and reader.namespaceWebhooks for the subgroup. BOTH CONTAINER IDS ANSWER IT — the vendored document restricts the operation to no particular group, so the subgroup is not denied a family this host lists it under (invariant #5) — and what each holds is a different fact: the organization's is the account-wide feed with all six delivery events, and the subgroup's is the hook every real account has one of, wired up once and never fired, because the subgroup owns no repository (founder ruling F1 of 2026-09-09). That one renders with every event flag FALSE and `alert_status: disabled`, which is GitLab's own vocabulary for a hook that will not deliver — APIEntitiesGroupHook carries no `active` property — and conformance asserts it rather than testing the family only where it is busy. The event-name translation is the project row's, plus the three flags only a group can publish (subgroup_events, member_events, project_events), all false. Gated on hasWebhookFilters()", mode_reviewed: "2026-09-12", tag: "Hooks" }
      - { method: "GET", path: "/api/v4/groups/{id}/hooks/{hook_id}", area: "hooks-config", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-18): the same group hook by id, byte-identical to the row the list publishes. The id must belong to the container named in the path: the subgroup's hook id is GitLab's 404 on the organization's path and the other way round, which conformance drives from both sides. Gated on hasWebhookFilters()", mode_reviewed: "2026-09-12", tag: "Hooks" }
      - { method: "GET", path: "/api/v4/groups/{id}/hooks/{hook_id}/events", area: "hooks-config", tier: 2, status: "deferred", mode: "generate", mode_reason: "RE-SCOPED 2026-09-12 by the hello-18 webhook wave, which served the four hook rows beside this one. The old reason (\"canon has no Webhook\") is now FALSE: canon carries webhook_subscription with the git hosts' three scopes as of hello-18, and this host serves the subscriptions. What is missing is a DELIVERY LOG — one row per attempted POST, with the request it sent and the response it got — which is a second entity hello-18 deliberately did not invent (decisions/2026-09-12-1125). The subscription's last_delivery_epoch/code/status are a fact about the SUBSCRIPTION, published on the subscription by every host in the fleet, and one row is not a log to page. THE ASK: a canon DeliveryAttempt hanging off webhook_subscription, and this row goes green off it", mode_reviewed: "2026-09-12", tag: "Hooks" }
      - { method: "GET", path: "/api/v4/groups/{id}/integrations", area: "integrations", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Integration; this universe literally has a Jira and a Slack to be integrated with", mode_reviewed: "2026-09-01", tag: "Integrations", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/integrations/{slug}", area: "integrations", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Integration; this universe literally has a Jira and a Slack to be integrated with", mode_reviewed: "2026-09-01", tag: "Integrations", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/invitations", area: "groups", tier: 1, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W3): the OUTSTANDING invitations on this group - reader.listMemberships('org', org) restricted to state pending with no person, an invitee_email and no failed_epoch. GitHub serves exactly these rows at /orgs/{org}/invitations, so the two hosts name the same outstanding offers. A LAPSED offer is excluded and the exclusion is asserted: canon marks an expired invitation with failed_epoch and GitHub publishes those separately, while GitLab has no failed-invitation surface at all - listing one as pending would tell a client an offer can still be accepted when it cannot. `invite_token` is omitted and always will be: it is the secret a recipient redeems the invitation with, and canon's no-secret contract means no row carries one. `user_name` is omitted because every invitation here was sent to an ADDRESS with no account behind it. `access_level` is the integer real GitLab sends where the component types it string, so the row is a deviation. The subgroup resolves and answers its own set. The old reason - a new canon entity Invitation is needed - was falsified by hello-16's membership domain, which models an invitation as a pending membership with an address", mode_reviewed: "2026-09-12", tag: "Invitations" }
      - { method: "GET", path: "/api/v4/groups/{id}/invited_groups", area: "groups", tier: 1, status: "green", mode: "empty", mode_reason: "an INVITATION between groups is an action and canon records none, so no group here has been invited to another. THE SUBGROUP RESOLVES HERE as of 2026-09-10 and answers the same empty list, for the same reason", mode_reviewed: "2026-09-10", tag: "Groups" }
      - { method: "GET", path: "/api/v4/groups/{id}/issues", area: "groups", tier: 1, status: "deviation", mode: "derive", mode_reason: "every issue in the organization's projects. THE SUBGROUP RESOLVES HERE as of 2026-09-10 and answers `200 []`: it owns no repository (founder ruling F1, 2026-09-09) and has no subgroup of its own, so the rollup is empty BY CONSTRUCTION rather than by a gap — the artifact asserts `repo.namespace IS NULL` on every row and conformance re-checks it", mode_reviewed: "2026-09-10", tag: "Groups" }
      - { method: "GET", path: "/api/v4/groups/{id}/issues_statistics", area: "groups", tier: 1, status: "green", mode: "derive", mode_reason: "the counts over the same rows the group issue list serves. THE SUBGROUP RESOLVES HERE as of 2026-09-10 and answers REAL ZEROS — `{all: 0, closed: 0, opened: 0}` — rather than an empty object: a group whose issue list is empty has zero of each, which is what real GitLab returns", mode_reviewed: "2026-09-10", tag: "Groups" }
      - { method: "GET", path: "/api/v4/groups/{id}/iterations", area: "iterations", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W8): a GitLab iteration IS canon's sprint — reader.listSprints() — which is the same object Jira serves as a Sprint and Azure DevOps as an iteration path, so the 27 windows and their dates are one set read three ways (invariant #5). THE iid IS GROUP-WIDE AND `sequence` IS PER-CADENCE, and that is the one decision this mapping makes: `sprint.idx` counts within a TEAM and four teams each run their own series, so `idx` repeats four times over and cannot be an iid GitLab guarantees unique inside a group — an iteration cadence being exactly one team's series, `sequence` IS `sprint.idx` and the iid is the group-wide rank by start date, ties broken by team and then by index so the numbering is total and stable. `state` is GitLab's INTEGER enum (started 2, closed 3); nothing here is ever upcoming, because the generator closes a sprint whose end falls before the window's end and starts none after it. `title` and `description` are OMITTED, and that is GitLab's own shape rather than a gap: iteration titles were removed in GitLab 15.6 and the field has been nullable since. `created_at`/`updated_at` are omitted because canon's sprint carries no instant beyond its start and end. `state=` is a real narrowing; `upcoming` truthfully matches nothing, the posture `pipelines?status=` already takes for an enum member this generator never produces", mode_reviewed: "2026-09-12", tag: "Iterations", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/labels", area: "labels", tier: 1, status: "green", mode: "derive", mode_reason: "features.namespaces (hello-16) puts two cross-cutting labels on the subgroup; reader.labelsForNamespace(id) derives them with is_project_label false. The organization's own list is empty and include_descendant_groups reaches the subgroup's, which is GitLab's own rule; older pins answer the empty list. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", tag: "Labels" }
      - { method: "GET", path: "/api/v4/groups/{id}/labels/{name}", area: "labels", tier: 1, status: "green", mode: "derive", mode_reason: "the by-name twin of the group label list, off the same reader.labelsForNamespace rows; a name nobody holds is still GitLab's 404 Label Not Found, and that is the whole answer on every pin older than hello-16. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", tag: "Labels" }
      - { method: "GET", path: "/api/v4/groups/{id}/ldap_group_links", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "LDAP", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/manage/personal_access_tokens", area: "group credentials inventory", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-18): the credentials of this group's ENTERPRISE USERS, which the vendored document scopes the operation to in as many words. The set is the same sixteen people /enterprise_users answers and the rows are the person_credential rows they already hold — the same rows /users/{id}/keys and /personal_access_tokens serve, re-scoped to the directory's people rather than re-derived, and conformance asserts every row is also on its owner's own list so the inventory and the person cannot disagree. THE MACHINE ACCOUNT'S CREDENTIALS ARE NOT HERE, which is what the exclusion is for: an inventory scoped to enterprise users must not list a principal the enterprise-user surface says does not exist. The vendored operation declares `200: OK` and NO response schema at all — a real GitLab spec gap — so the shape is glPersonalAccessToken, the same object /personal_access_tokens serves, and conformance asserts every id, name, owner and active flag against the credential row rather than against a schema that does not exist. The subgroup gets GitLab's own not_found!, on the vendored description's own top-level scoping. Gated on hasExternalUid() (the set) and hasCredentials() (the rows); an older artifact answers the named generation gap rather than []", mode_reviewed: "2026-09-12", tag: "Group credentials inventory", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/manage/resource_access_tokens", area: "group credentials inventory", tier: 3, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-10 (hello-16): \"all group and project access tokens associated with a TOP-LEVEL-GROUP\" — the group token plus every project token below it, from the same two reader.listCredentials calls, and conformance asserts the managed list is exactly the UNION of the narrower ones so a token cannot appear here without appearing on its own container. THE SUBGROUP GETS GITLAB'S 404 rather than a list: the document restricts the operation to a top-level group, and an empty list would report a different fact from the one the provider reports. Gated on hasCredentials()", mode_reviewed: "2026-09-10", tag: "Group credentials inventory", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/manage/ssh_keys", area: "group credentials inventory", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-18): the credentials of this group's ENTERPRISE USERS, which the vendored document scopes the operation to in as many words. The set is the same sixteen people /enterprise_users answers and the rows are the person_credential rows they already hold — the same rows /users/{id}/keys and /personal_access_tokens serve, re-scoped to the directory's people rather than re-derived, and conformance asserts every row is also on its owner's own list so the inventory and the person cannot disagree. THE MACHINE ACCOUNT'S CREDENTIALS ARE NOT HERE, which is what the exclusion is for: an inventory scoped to enterprise users must not list a principal the enterprise-user surface says does not exist. AUTHENTICATION KEYS ONLY: the operation's own words are \"all SSH public keys associated with enterprise users\", and canon's `ssh-signing` rows are excluded on the ruling /users/{selected_user}/ssh-keys already carries one host over — a key authorised to push and a key trusted to attest authorship are different grants, and an inventory is the first place conflating them would matter. APIEntitiesSshKeyWithUserId declares seven properties and the key MATERIAL is not one of them, so it is absent rather than repeated: this route answers WHO HOLDS WHAT and /users/{id}/keys is where the bytes are. The subgroup gets GitLab's own not_found!, on the vendored description's own top-level scoping. Gated on hasExternalUid() (the set) and hasCredentials() (the rows); an older artifact answers the named generation gap rather than []", mode_reviewed: "2026-09-12", tag: "Group credentials inventory", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/member_roles", area: "member roles", tier: 3, status: "green", mode: "empty", mode_reason: "olympus-labs defines no custom member role — the five roles in canon's membership_role table are GitLab's own built-ins; GitLab answers `[]` at 200 for a group that has minted none. THE LIST HALF, served UNPAGINATED because the vendored operation declares `id` and nothing else. Both container ids answer it: the document restricts the operation to no particular group, so the subgroup is not denied a family this host lists it under (invariant #5). UNGATED: no generation of this universe mints a custom role — canon's five roles are GitLab's own built-ins. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Member roles", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/members", area: "groups", tier: 1, status: "green", mode: "derive", mode_reason: "reader.orgMembers() for the organization's own group. THE SUBGROUP RESOLVES HERE as of 2026-09-10 and answers `200 []`: the vendored document is explicit that this lists \"all DIRECT members ... does not return inherited members from ancestor groups\", and no `membership` row in this artifact scopes to a namespace (decisions/2026-09-09-1742). /members/all, which DOES include ancestors, answers the full roster for it — the two are GitLab's own split rather than one of them being a stub. Before 2026-09-10 this row answered `404 Group Not Found` for an id the same host lists, which was invariant #5 failing from the inside", mode_reviewed: "2026-09-10", tag: "Members" }
      - { method: "GET", path: "/api/v4/groups/{id}/members/{user_id}", area: "groups", tier: 1, status: "green", mode: "derive", mode_reason: "one DIRECT member of the group. THE SUBGROUP RESOLVES HERE as of 2026-09-10 and answers `404 Not found` for every person: it has no direct member, which is the same fact its list row reports as `[]`. The inherited form /members/all/{user_id} is where an organization member resolves", mode_reviewed: "2026-09-10", tag: "Members" }
      - { method: "GET", path: "/api/v4/groups/{id}/members/all", area: "groups", tier: 1, status: "green", mode: "derive", mode_reason: "the direct-plus-INHERITED listing over one membership table. THE SUBGROUP RESOLVES HERE as of 2026-09-10 and answers the ORGANIZATION'S FULL ROSTER for it, which is the vendored document's own semantics — \"also returns inherited members from ancestor groups\" — and the one family in this sweep where the parent's data flows DOWN rather than the child being empty", mode_reviewed: "2026-09-10", tag: "Members" }
      - { method: "GET", path: "/api/v4/groups/{id}/members/all/{user_id}", area: "groups", tier: 1, status: "green", mode: "derive", mode_reason: "one member of the direct-plus-inherited listing. THE SUBGROUP RESOLVES HERE as of 2026-09-10 and resolves every organization member through inheritance, matching its own list row; the DIRECT-only twin /members/{user_id} answers GitLab's 404 there instead", mode_reviewed: "2026-09-10", tag: "Members" }
      - { method: "GET", path: "/api/v4/groups/{id}/merge_request_approval_setting", area: "merge-requests", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): the group-level setting is its projects' rules read from above - GitLab's own cascade, where a group setting governs every project the group owns and a subgroup inherits its parent's. This organization owns one project, so the rules in scope are that project's and both group ids answer the same body. One field, for the reason the project twin gives", mode_reviewed: "2026-09-12", tag: "Merge request approvals" }
      - { method: "GET", path: "/api/v4/groups/{id}/merge_requests", area: "merge-requests", tier: 1, status: "deviation", mode: "derive", mode_reason: "\"all merge requests for a specified group AND ANY SUBGROUPS\", which for the organization is every merge request in the universe. THE SUBGROUP RESOLVES HERE as of 2026-09-10 and answers `200 []`: it owns no project and has no subgroup below it (founder ruling F1)", mode_reviewed: "2026-09-10", tag: "Merge requests" }
      - { method: "GET", path: "/api/v4/groups/{id}/milestones", area: "milestones", tier: 1, status: "deviation", mode: "derive", mode_reason: "features.namespaces (hello-16) puts the release train the repository's milestone rolls up into on the subgroup; reader.milestonesForNamespace(id) derives it with group_id and its own iid. Older pins answer the empty list. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", tag: "Milestones" }
      - { method: "GET", path: "/api/v4/groups/{id}/milestones/{milestone_id}", area: "milestones", tier: 1, status: "deviation", mode: "derive", mode_reason: "the by-id twin of the group milestone list, off the same reader.milestonesForNamespace row; an id nobody holds is still GitLab's 404 Milestone Not Found, and that is the whole answer on every pin older than hello-16. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", tag: "Milestones" }
      - { method: "GET", path: "/api/v4/groups/{id}/milestones/{milestone_id}/burndown_events", area: "milestones", tier: 1, status: "planned", mode: "generate", mode_reason: "canon keeps current label/milestone state, not its history; needs a ResourceEvent log", mode_reviewed: "2026-09-01", tag: "Milestones" }
      - { method: "GET", path: "/api/v4/groups/{id}/milestones/{milestone_id}/issues", area: "milestones", tier: 1, status: "green", mode: "empty", mode_reason: "the group milestone RESOLVES from hello-16 and nothing is assigned to it: it is the release train the repository's own milestone rolls up into, and all 24 issues that carry a milestone carry the repository's. Served as GitLab's 200 [] under a milestone that exists, rather than the 404 it was when no group milestone could exist - which is still the answer on every older pin. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", tag: "Milestones" }
      - { method: "GET", path: "/api/v4/groups/{id}/milestones/{milestone_id}/merge_requests", area: "milestones", tier: 1, status: "green", mode: "empty", mode_reason: "the merge-request twin of the group milestone's issue list, empty for the same reason: both merge requests that carry a milestone carry the REPOSITORY's, which projects/{id}/milestones/{id}/merge_requests serves with real rows. 200 [] under a milestone that exists from hello-16; the 404 on every older pin. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", tag: "Milestones" }
      - { method: "GET", path: "/api/v4/groups/{id}/notification_settings", area: "notification settings", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no NotificationSetting for a persona", mode_reviewed: "2026-09-01", tag: "Notification settings", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/packages", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages" }
      - { method: "GET", path: "/api/v4/groups/{id}/pending_members", area: "groups", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W3): the same rows /api/v4/groups/{id}/invitations serves, in GitLab's pending-member shape. THIS CORRECTS A FALSIFIED EMPTY: the row was terminal on the reason that this group has no outstanding invitation, and the artifact carries two org-scope memberships that are pending with an invitee_email - one of which GitHub has served at /orgs/{org}/invitations since the hello-16 access wave. The vendored description is the wider operation - members in an awaiting state AND those invited without a GitLab account, across the group and any subgroups and projects - and this universe makes the two coincide: canon has no awaiting state (a Membership is active or pending, and a pending one with an address is an invitation) and no subgroup- or project-scoped pending row exists, which conformance asserts rather than assumes. `invited` is person IS NULL AND invitee_email IS NOT NULL; `approved` is true because nobody here is awaiting an administrator's approval, a state canon models nowhere; `name`, `username` and `web_url` are omitted because there is no account to name. The vendored operation declares no schema, so those assertions are the row's whole check. THE SUBGROUP STILL ANSWERS GitLab's 404 - the document says the operation works on top-level groups only. Every artifact without the membership domain goes on answering the same empty list it always did, because reader.listMemberships returns nothing there", mode_reviewed: "2026-09-12", tag: "Members" }
      - { method: "GET", path: "/api/v4/groups/{id}/placeholder_reassignments", area: "groups", tier: 1, status: "green", mode: "empty", mode_reason: "a pending reassignment is an IMPORT artifact and this group was never imported from another instance. THE SUBGROUP RESOLVES HERE as of 2026-09-10 and answers the same empty list, for the same reason", mode_reviewed: "2026-09-10", tag: "Groups" }
      - { method: "GET", path: "/api/v4/groups/{id}/projects", area: "groups", tier: 1, status: "green", mode: "derive", mode_reason: "the projects a group owns. The organization owns the one repository; the hello-16 subgroup owns NONE by founder ruling F1 (repo.namespace is null on every row), so this list is truthfully empty for it and the row resolves both group ids rather than 404ing one of them.", mode_reviewed: "2026-09-09", tag: "Groups" }
      - { method: "GET", path: "/api/v4/groups/{id}/projects/shared", area: "groups", tier: 1, status: "green", mode: "empty", mode_reason: "the organization owns every project directly and none is shared in from anywhere. THE SUBGROUP RESOLVES HERE as of 2026-09-10 and answers the same empty list: it owns no project of its own (founder ruling F1) and nothing has been shared with it either", mode_reviewed: "2026-09-10", tag: "Groups" }
      - { method: "GET", path: "/api/v4/groups/{id}/protected_branches", area: "protected-branches", tier: 2, status: "green", mode: "derive", mode_reason: "features.namespaces (hello-16) adds protected_ref, a rule over a ref PATTERN at namespace scope - two rows, main and release/*. reader.protectedRefs('namespace', id) derives them; older pins answer the empty list. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", tag: "Protected branches" }
      - { method: "GET", path: "/api/v4/groups/{id}/protected_branches/{name}", area: "protected-branches", tier: 2, status: "green", mode: "derive", mode_reason: "the by-name twin of the group protection list, off the same reader.protectedRefs rows and accepting a url-encoded pattern (release%2F*); a pattern nobody holds is still GitLab's 404, and that is the whole answer on every pin older than hello-16. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", tag: "Protected branches" }
      - { method: "GET", path: "/api/v4/groups/{id}/protected_environments", area: "deployments", tier: 2, status: "green", mode: "empty", mode_reason: "olympus-labs protects only branches — canon's protected_ref carries two branch patterns at namespace scope and no environment, tag, merge train, push rule or external status check exists; GitLab answers `[]` at 200 for each of these lists and its own 404 for a named one. THE LIST HALF, served as GitLab's empty page with the pagination headers the operation declares. UNGATED: no generation of this universe has ever protected an environment or a tag, queued a merge train, registered an external status check or set a push rule, so every registered pin answers this same `[]`. Falsifiable: the `expectsEmpty` conformance entry reds the row the day canon grows one. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Protected environments" }
      - { method: "GET", path: "/api/v4/groups/{id}/protected_environments/{name}", area: "deployments", tier: 2, status: "deferred", mode: "refuse", mode_reason: "olympus-labs protects only branches — canon's protected_ref carries two branch patterns at namespace scope and no environment, tag, merge train, push rule or external status check exists; GitLab answers `[]` at 200 for each of these lists and its own 404 for a named one. THE NAMED HALF: no name resolves over a collection that is empty, so GitLab's own 404 is the whole answer — `[]` here would assert that the thing exists and holds nothing. UNGATED: no generation of this universe has ever protected an environment or a tag, queued a merge train, registered an external status check or set a push rule, so the 404 is true on every artifact. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Protected environments" }
      - { method: "GET", path: "/api/v4/groups/{id}/provisioned_users", area: "groups", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-18): THE SAME SIXTEEN PEOPLE ANSWER saml_users, provisioned_users AND enterprise_users, and that is GitLab's own definition rather than a shortcut: an enterprise user is one the group provisioned through its own SAML/SCIM, and a SAML user and a provisioned user are that sentence read from the other two ends. canon carries ONE identity_provider_config (protocol saml, scim_enabled 1) and one external_uid per person, so the three lists are one set and conformance asserts they are identical rather than leaving it a coincidence. THE MACHINE ACCOUNT IS EXCLUDED and that is the domain's load-bearing ruling (decisions/2026-09-12-1120): canon writes no external_uid for the CI bot, because a directory provisions humans and GitLab's word for a machine principal is a SERVICE ACCOUNT — a different object, a different API family, and one five armed `…/service_accounts` rulings say this universe does not mint. The rows are glUser, byte-identical to what /api/v4/users/{id} serves for each of them, which conformance checks person by person. THE SUBGROUP RESOLVES THIS ONE AND ANSWERS []: it is the one of the three the vendored document does NOT restrict to a top-level group, and a subgroup runs no directory of its own, so it has provisioned nobody. Gated on hasExternalUid(); an older artifact answers the named hello-18 identity gap rather than [], because an empty list there would say nobody here was provisioned by a directory while this same host publishes a SAML configuration with SCIM enabled — the replica disagreeing with itself (invariant #5)", mode_reviewed: "2026-09-12", tag: "Groups" }
      - { method: "GET", path: "/api/v4/groups/{id}/push_rule", area: "push rules", tier: 3, status: "deferred", mode: "refuse", mode_reason: "olympus-labs protects only branches — canon's protected_ref carries two branch patterns at namespace scope and no environment, tag, merge train, push rule or external status check exists; GitLab answers `[]` at 200 for each of these lists and its own 404 for a named one. NOT A NAMED HALF AND NOT A COLLECTION: `push_rule` is a SINGULAR sub-resource that takes no name, so `[]` is not a shape it can take at all — there is simply no rule object to render, and the vendored operation declares exactly two responses, a 200 with the rule and a 404 without one. UNGATED: no generation of this universe has ever protected an environment or a tag, queued a merge train, registered an external status check or set a push rule. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Push rules", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/registry/repositories", area: "container-registry", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Container registry" }
      - { method: "GET", path: "/api/v4/groups/{id}/related_epic_links", area: "epics", tier: 2, status: "deferred", mode: "generate", mode_reason: "STILL BLOCKED 2026-09-12 (hello-17): the group-wide list of the same epic-to-epic relation /epics/{epic_iid}/related_epics enumerates per epic, and blocked by the same single fact - issue_link links two ISSUES, and canon's only epic-to-epic relation is parentage. THE ASK is that row's", mode_reviewed: "2026-09-12", tag: "Epics" }
      - { method: "GET", path: "/api/v4/groups/{id}/releases", area: "releases", tier: 1, status: "green", mode: "derive", mode_reason: "\"all releases for PROJECTS IN a specified group\" — the same rows each project's own /releases serves. THE SUBGROUP RESOLVES HERE as of 2026-09-10 and answers `200 []`, because it owns no project (founder ruling F1)", mode_reviewed: "2026-09-10", tag: "Releases" }
      - { method: "GET", path: "/api/v4/groups/{id}/repository_storage_moves", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Storage moves", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/repository_storage_moves/{repository_storage_move_id}", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Storage moves", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/runners", area: "runners", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon's jobs ran on nothing; needs a Runner the job table can point at", mode_reviewed: "2026-09-01", tag: "Runners" }
      - { method: "GET", path: "/api/v4/groups/{id}/saml_group_links", area: "saml group links", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): the groups this organization's directory asserts and what each may do here — APIEntitiesSamlGroupLink over canon's identity_group (the asserted group, hello-15) joined to its one membership row at scope_kind = 'group' (hello-17). `access_level` maps canon's five role keys onto GitLab's own five constants by what the role's permissions column actually grants: owner 50, admin 40, maintainer 40, member 30, reader 10. `provider` is the directory's own protocol rather than a literal, so a universe that ever ran OIDC would say so. `member_role_id` IS OMITTED and that is a statement: it names a CUSTOM member role, olympus-labs mints none — /groups/{id}/member_roles is armed `empty` on exactly that fact — and an id here would address a role this host says does not exist. A group with no role is not linked at all rather than linked at an invented level. GATED ON THE DIRECTORY AND ON hasGrants(), NOT ON hasExternalUid(), and that is the wave's one deliberate asymmetry: a SAML group link names a GROUP, not a person, so it needs identity_group (hello-15) and the group's own role (hello-17 features.grants, reader.groupRole) and no per-person handle at all. Both halves are already on the LIVE artifact, so these two rows answer TODAY rather than waiting for hello-18's cutover — gating them on a uid they do not read would have reported a gap for a fact that is present. The subgroup answers [] for the list and GitLab's 404 for a named link: the directory hangs off the organization", mode_reviewed: "2026-09-12", tag: "SAML group links", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/saml_group_links/{saml_group_name}", area: "saml group links", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): one link by the directory group's name, byte-identical to its entry in the list. `?provider=` IS HONOURED RATHER THAN IGNORED: naming this directory's own protocol narrows to the same link and naming one nobody runs is GitLab's 404, which conformance drives both ways — a silently-ignored filter that still answered 200 is the wrong answer this renderer refuses to give. A name the directory does not assert is GitLab's own 404. GATED ON THE DIRECTORY AND ON hasGrants(), NOT ON hasExternalUid(), and that is the wave's one deliberate asymmetry: a SAML group link names a GROUP, not a person, so it needs identity_group (hello-15) and the group's own role (hello-17 features.grants, reader.groupRole) and no per-person handle at all. Both halves are already on the LIVE artifact, so these two rows answer TODAY rather than waiting for hello-18's cutover — gating them on a uid they do not read would have reported a gap for a fact that is present. The subgroup answers [] for the list and GitLab's 404 for a named link: the directory hangs off the organization", mode_reviewed: "2026-09-12", tag: "SAML group links", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/saml_users", area: "groups", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-18): THE SAME SIXTEEN PEOPLE ANSWER saml_users, provisioned_users AND enterprise_users, and that is GitLab's own definition rather than a shortcut: an enterprise user is one the group provisioned through its own SAML/SCIM, and a SAML user and a provisioned user are that sentence read from the other two ends. canon carries ONE identity_provider_config (protocol saml, scim_enabled 1) and one external_uid per person, so the three lists are one set and conformance asserts they are identical rather than leaving it a coincidence. THE MACHINE ACCOUNT IS EXCLUDED and that is the domain's load-bearing ruling (decisions/2026-09-12-1120): canon writes no external_uid for the CI bot, because a directory provisions humans and GitLab's word for a machine principal is a SERVICE ACCOUNT — a different object, a different API family, and one five armed `…/service_accounts` rulings say this universe does not mint. The rows are glUser, byte-identical to what /api/v4/users/{id} serves for each of them, which conformance checks person by person. THE SUBGROUP GETS GITLAB'S OWN not_found!: the vendored description scopes this operation to a specified TOP-LEVEL group, so the operation does not exist for a subgroup — a different fact from having nothing to list, and the one the provider reports (the per-family table of decisions/2026-09-10). Gated on hasExternalUid(); an older artifact answers the named hello-18 identity gap rather than [], because an empty list there would say nobody here was provisioned by a directory while this same host publishes a SAML configuration with SCIM enabled — the replica disagreeing with itself (invariant #5)", mode_reviewed: "2026-09-12", tag: "Groups" }
      - { method: "GET", path: "/api/v4/groups/{id}/saml/{uid}", area: "provider identities", tier: 3, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-18): one identity by the handle itself — THE ROW THE WHOLE DOMAIN WAS ASKED FOR, since a uid that resolves to a person instead of to nothing is what this clique has named as its blocker since 2026-09-09. Byte-identical to that person's entry in the list, which conformance compares directly; a handle of the right SHAPE that nobody holds is GitLab's own 404, so the refusal is about the value rather than about the path. Same deviation as its list. The subgroup resolves the family — the document restricts it to no particular group — and answers [] for a list and GitLab's 404 for a named read, because a subgroup federates nobody; the organization above it does. Gated on hasExternalUid(); an older artifact answers the named hello-18 identity gap rather than [], because an empty list there would say nobody here was provisioned by a directory while this same host publishes a SAML configuration with SCIM enabled — the replica disagreeing with itself (invariant #5)", mode_reviewed: "2026-09-12", tag: "Provider identities", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/saml/identities", area: "provider identities", tier: 3, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-18): the directory identities themselves — APIEntitiesIdentityDetail over person.external_uid, a 32-character lowercase hex handle (a UUID with its hyphens removed, which is the width Entra and Okta issue) that is a pure function of the root seed and the person's id. DEVIATION RATHER THAN GREEN, and the evidence is the vendored document contradicting itself: APIEntitiesIdentityDetail types `user_id` and `active` as `string`, while GitLab's own published example for these operations is {\"extern_uid\": \"4\", \"user_id\": 48, \"active\": true} — an integer and a boolean. Invariant #2 mirrors the provider rather than its documentation, so the real types are served and the two errors are declared spec bugs. `active` is true on every row because canon records no deprovisioning. Conformance asserts every handle matches /^[0-9a-f]{32}$/, that no two people share one, and that every user_id resolves to a person this host serves. The subgroup resolves the family — the document restricts it to no particular group — and answers [] for a list and GitLab's 404 for a named read, because a subgroup federates nobody; the organization above it does. Gated on hasExternalUid(); an older artifact answers the named hello-18 identity gap rather than [], because an empty list there would say nobody here was provisioned by a directory while this same host publishes a SAML configuration with SCIM enabled — the replica disagreeing with itself (invariant #5)", mode_reviewed: "2026-09-12", tag: "Provider identities", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/scim/{uid}", area: "provider identities", tier: 3, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-18): one SCIM identity by the handle, byte-identical to the SAML identity for the same handle — one directory, one identity, asserted rather than assumed. Same deviation as its list. The subgroup resolves the family — the document restricts it to no particular group — and answers [] for a list and GitLab's 404 for a named read, because a subgroup federates nobody; the organization above it does. Gated on hasExternalUid(); an older artifact answers the named hello-18 identity gap rather than [], because an empty list there would say nobody here was provisioned by a directory while this same host publishes a SAML configuration with SCIM enabled — the replica disagreeing with itself (invariant #5)", mode_reviewed: "2026-09-12", tag: "Provider identities", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/scim/identities", area: "provider identities", tier: 3, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-18): the directory identities themselves — APIEntitiesIdentityDetail over person.external_uid, a 32-character lowercase hex handle (a UUID with its hyphens removed, which is the width Entra and Okta issue) that is a pure function of the root seed and the person's id. DEVIATION RATHER THAN GREEN, and the evidence is the vendored document contradicting itself: APIEntitiesIdentityDetail types `user_id` and `active` as `string`, while GitLab's own published example for these operations is {\"extern_uid\": \"4\", \"user_id\": 48, \"active\": true} — an integer and a boolean. Invariant #2 mirrors the provider rather than its documentation, so the real types are served and the two errors are declared spec bugs. `active` is true on every row because canon records no deprovisioning. THE SCIM IDENTITIES ARE THE SAME IDENTITIES, and that is what one directory means: canon holds a single identity_provider_config with scim_enabled = 1, so a second, different handle here would assert a second directory nobody configured. Conformance compares the two lists element for element. The subgroup resolves the family — the document restricts it to no particular group — and answers [] for a list and GitLab's 404 for a named read, because a subgroup federates nobody; the organization above it does. Gated on hasExternalUid(); an older artifact answers the named hello-18 identity gap rather than [], because an empty list there would say nobody here was provisioned by a directory while this same host publishes a SAML configuration with SCIM enabled — the replica disagreeing with itself (invariant #5)", mode_reviewed: "2026-09-12", tag: "Provider identities", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/service_accounts", area: "service accounts", tier: 3, status: "green", mode: "empty", mode_reason: "every actor in olympus-labs is a person on the roster — canon mints no bot principal, and a service account served here would be a member no other host lists (invariant #5); GitLab answers `[]` at 200 for a group with none. THE LIST HALF, served as GitLab's empty page with the pagination headers the operation declares. UNGATED: canon has no `ServiceAccount` in any generation — hello-17 dropped the federation domain that would have introduced one, so every registered pin answers this same `[]`. Falsifiable: the `expectsEmpty` conformance entry reds the row the day canon grows one. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Service accounts", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/groups/{id}/service_accounts/{user_id}/personal_access_tokens", area: "deploy-keys-tokens", tier: 3, status: "deferred", mode: "refuse", mode_reason: "every actor in olympus-labs is a person on the roster — canon mints no bot principal, and a service account served here would be a member no other host lists (invariant #5); GitLab answers `[]` at 200 for a group with none. THE NAMED HALF: `{user_id}` names a service account, and no service account exists to be named — so this operation never reaches a token list to be empty of and GitLab's own 404 is the whole answer. UNGATED: canon has no `ServiceAccount` in any generation — hello-17 dropped the federation domain that would have introduced one. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Access tokens" }
      - { method: "GET", path: "/api/v4/groups/{id}/ssh_certificates", area: "deploy-keys-tokens", tier: 3, status: "green", mode: "empty", mode_reason: "a group SSH CERTIFICATE is a certificate AUTHORITY an administrator registers so members can authenticate with short-lived certificates. Registering one is an ACTION and canon records none in any generation; every `ssh-auth` row in reader.listCredentials is a plain ed25519 public key rather than a certificate, which is the same fact read from the members' end. SERVED 2026-09-10 as GitLab's empty page with the pagination headers the vendored operation's page/per_page declare, UNGATED — the fact is a property of the model rather than of the credential domain, so an older artifact answers the same empty list. The vendored document scopes this operation to \"a specified group\" and not to a top-level one, so the subgroup answers it too. RULED by the founder 2026-09-10", mode_reviewed: "2026-09-10", tag: "Keys" }
      - { method: "GET", path: "/api/v4/groups/{id}/subgroups", area: "groups", tier: 1, status: "deviation", mode: "derive", mode_reason: "features.namespaces (hello-16) gives this organization one subgroup, so reader.listNamespaces(parent) answers a real child. The 2026-09-09 empty said a subgroup was on hello-16 and this is that generation; older pins still answer the empty list, which is what they truthfully hold. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", tag: "Groups" }
      - { method: "GET", path: "/api/v4/groups/{id}/transfer_locations", area: "groups", tier: 1, status: "green", mode: "empty", mode_reason: "the namespaces a GROUP can be transferred into. Empty for the organization because a group cannot be transferred into its own descendant and the only other namespace is one. THE SUBGROUP RESOLVES HERE as of 2026-09-10 and is empty for the OPPOSITE reason, which is why this row now carries both: the only candidate for the subgroup is the parent it already sits under, and a transfer that moves nothing is no transfer. Neither emptiness is a gap", mode_reviewed: "2026-09-10", tag: "Groups" }
      - { method: "GET", path: "/api/v4/groups/{id}/uploads", area: "groups", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-18): the group's own uploads — reader.namespaceUploads. THE ROOT GROUP HOLDS NONE AND THE SUBGROUP HOLDS ONE, which is the split /groups/{id}/labels already makes and is a fact rather than a gap: a group-level upload belongs to the CONTAINER it was attached to, and canon attaches its one such file — the chart of the release the subgroup was created around — to the subgroup. So the root answers [] at 200 (the group resolves, it simply has nothing attached) and the subgroup answers its file; conformance drives BOTH ids and asserts each. Gated on hasAttachmentParents(); an older artifact answers the named hello-18 upload gap rather than [], because [] there would say nobody here ever attached a file — false of the story every generation tells, where only the PARENT column was missing", mode_reviewed: "2026-09-12", tag: "Groups" }
      - { method: "GET", path: "/api/v4/groups/{id}/uploads/{secret}/{filename}", area: "groups", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-18): the FILE. The vendored operation declares no response schema at all, because the body is the bytes: this route answers the artifact's own attachment.body verbatim, with the artifact's own content_type and `Content-Disposition: attachment` naming the file. The disposition is `attachment` for every kind rather than a branch this host guesses at — GitLab serves an upload inline only for a type on its own safe list, and image/svg+xml, which every image in this canon carries, is explicitly not on it because an SVG can carry script. Conformance re-reads the artifact row and asserts the served bytes are identical to it and that their length is the `size` the list advertised. THE `secret` IS THE FILE'S OWN DIGEST, first 32 characters. GitLab mints a 32-character hex token per upload and canon mints none; an invented one would be a value no client could cross-check, while the first half of attachment.sha256 — measured from the body at compile — is 32 hex characters, is a pure function of the bytes it addresses, and is reproducible by any caller that has downloaded the file. Conformance asserts the secret address and the id address serve the same bytes, and that a secret which is not this file's digest is GitLab's own 404. Gated on hasAttachmentParents(); an older artifact answers the named hello-18 upload gap", mode_reviewed: "2026-09-12", tag: "Groups" }
      - { method: "GET", path: "/api/v4/groups/{id}/uploads/{upload_id}", area: "groups", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-18): the FILE. The vendored operation declares no response schema at all, because the body is the bytes: this route answers the artifact's own attachment.body verbatim, with the artifact's own content_type and `Content-Disposition: attachment` naming the file. The disposition is `attachment` for every kind rather than a branch this host guesses at — GitLab serves an upload inline only for a type on its own safe list, and image/svg+xml, which every image in this canon carries, is explicitly not on it because an SVG can carry script. Conformance re-reads the artifact row and asserts the served bytes are identical to it and that their length is the `size` the list advertised. Scoped to the group named in the path, so a project upload's id is GitLab's 404 here exactly as a group upload's is on the project path. Gated on hasAttachmentParents(); an older artifact answers the named hello-18 upload gap", mode_reviewed: "2026-09-12", tag: "Groups" }
      - { method: "GET", path: "/api/v4/groups/{id}/variables", area: "variables", tier: 3, status: "green", mode: "derive", mode_reason: "the group's own CI/CD variables, off reader.orgCiBindings(org, 'pipeline') for the organization's top-level group and reader.namespaceCiBindings(ns) for the subgroup — two scopes, two sets, resolved through the one groupTarget every group family shares. A `selected` org binding is still a group variable here: visibility is GitHub's vocabulary and GitLab has none, a group variable reaching every project in the group — and conformance asserts that the selected set IS every repository this organization has, so the day a second one appears the row reds rather than over-serving. SERVED 2026-09-12 (hello-19 `ciBindings`): the 2026-09-09 re-scope asked for a variable table and named the constraint that would make one honest — a masked value is a secret canon stores none of. hello-19's `ci_binding` is that table, built on exactly that constraint: one row, one `masked` boolean, and NO VALUE IN ANY COLUMN on a masked row (`compiler/src/hello19.test.ts` asserts `COUNT(*) WHERE masked = 1 AND value IS NOT NULL` is 0 on every compiled artifact). A MASKED BINDING RENDERS `hidden: true` AND SHIPS NO `value` KEY, which is GitLab's own vocabulary rather than a convenience: `masked` means blanked out of JOB LOGS and `hidden` (created as `masked_and_hidden`) means THE API NEVER RETURNS THE VALUE, so `masked: true, hidden: false` with the key dropped would be a shape real GitLab never sends. An unmasked binding's `value` is the artifact row `ci_binding.value_source` names — the collector's endpoint, the default branch, the orb document's tree path — resolved at compile time, so the setting and the thing it configures cannot drift apart. `variable_type` is `env_var` on every row, which agrees with /api/v4/projects/{id}/secure_files being ruled empty: a `file` variable IS a secure file. `raw` and `description` are OMITTED rather than defaulted — neither is required by APIEntitiesCiVariable and neither is a fact canon holds (the depth-hooks.ts rule, one wave earlier). Conformance drives each row against the vendored schema AND against the reader accessor the renderer must have used, walks the pages with the headers asserted, and fails if a masked row ever carries a value. Gated on hasCiBindings(); an older artifact answers the named hello-19 CI-variable gap, because [] there would say this organization configures its pipelines with nothing while the same artifact publishes a CI document, a nightly schedule and deployments to two environments", mode_reviewed: "2026-09-12", tag: "CI variables" }
      - { method: "GET", path: "/api/v4/groups/{id}/variables/{key}", area: "variables", tier: 3, status: "green", mode: "derive", mode_reason: "the same group variable by key, byte-identical to the list's own row (conformance compares them), with the operation's own `404 Group Variable Not Found` for a key this scope does not hold — a subgroup's key on the organization's group included, because they are different scopes. NO decodeURIComponent on {key}: Hono has already decoded the segment, so a second decode would mis-match a key containing a percent sign and THROW on a malformed escape — `…/variables/%ZZ` is a key no variable has, answered 404. SERVED 2026-09-12 (hello-19 `ciBindings`): the 2026-09-09 re-scope asked for a variable table and named the constraint that would make one honest — a masked value is a secret canon stores none of. hello-19's `ci_binding` is that table, built on exactly that constraint: one row, one `masked` boolean, and NO VALUE IN ANY COLUMN on a masked row (`compiler/src/hello19.test.ts` asserts `COUNT(*) WHERE masked = 1 AND value IS NOT NULL` is 0 on every compiled artifact). A MASKED BINDING RENDERS `hidden: true` AND SHIPS NO `value` KEY, which is GitLab's own vocabulary rather than a convenience: `masked` means blanked out of JOB LOGS and `hidden` (created as `masked_and_hidden`) means THE API NEVER RETURNS THE VALUE, so `masked: true, hidden: false` with the key dropped would be a shape real GitLab never sends. An unmasked binding's `value` is the artifact row `ci_binding.value_source` names — the collector's endpoint, the default branch, the orb document's tree path — resolved at compile time, so the setting and the thing it configures cannot drift apart. `variable_type` is `env_var` on every row, which agrees with /api/v4/projects/{id}/secure_files being ruled empty: a `file` variable IS a secure file. `raw` and `description` are OMITTED rather than defaulted — neither is required by APIEntitiesCiVariable and neither is a fact canon holds (the depth-hooks.ts rule, one wave earlier). Conformance drives each row against the vendored schema AND against the reader accessor the renderer must have used, walks the pages with the headers asserted, and fails if a masked row ever carries a value. Gated on hasCiBindings(); an older artifact answers the named hello-19 CI-variable gap, because [] there would say this organization configures its pipelines with nothing while the same artifact publishes a CI document, a nightly schedule and deployments to two environments", mode_reviewed: "2026-09-12", tag: "CI variables" }
      - { method: "GET", path: "/api/v4/groups/{id}/wiki_pages/{noteable_id}/notes", area: "notes", tier: 1, status: "planned", mode: "refuse", mode_reason: "olympus-labs documents its services in the parthenon repository, not in a wiki — no WikiPage exists at project or group scope; GitLab answers `[]` at 200 for the wiki list and its own 404 for a slug that names nothing. THE SLUG/PAGE-ID HALF: no slug and no wiki_page_meta_id resolves, so GitLab's own 404 is the whole answer — a 200 `[]` on a wiki page's note list would assert that the page exists and nobody commented on it. UNGATED: canon has no WikiPage in any generation. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Notes" }
      - { method: "GET", path: "/api/v4/groups/{id}/wiki_pages/{noteable_id}/notes/{note_id}", area: "notes", tier: 1, status: "planned", mode: "refuse", mode_reason: "olympus-labs documents its services in the parthenon repository, not in a wiki — no WikiPage exists at project or group scope; GitLab answers `[]` at 200 for the wiki list and its own 404 for a slug that names nothing. THE SLUG/PAGE-ID HALF: no slug and no wiki_page_meta_id resolves, so GitLab's own 404 is the whole answer — a 200 `[]` on a wiki page's note list would assert that the page exists and nobody commented on it. UNGATED: canon has no WikiPage in any generation. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Notes" }
      - { method: "GET", path: "/api/v4/groups/{id}/wikis", area: "wikis", tier: 3, status: "green", mode: "empty", mode_reason: "olympus-labs documents its services in the parthenon repository, not in a wiki — no WikiPage exists at project or group scope; GitLab answers `[]` at 200 for the wiki list and its own 404 for a slug that names nothing. THE LIST HALF, served UNPAGINATED because the vendored operation declares only `id` and `with_content` — printing pagination headers on an operation GitLab does not paginate would break invariant #2 in the name of consistency. Both container ids answer it: the document says \"for a group\" and restricts the operation to no particular one, so the subgroup is not denied a family this host lists it under (invariant #5). UNGATED: canon has no WikiPage in any generation. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Wikis" }
      - { method: "GET", path: "/api/v4/groups/{id}/wikis/{slug}", area: "wikis", tier: 3, status: "deferred", mode: "refuse", mode_reason: "olympus-labs documents its services in the parthenon repository, not in a wiki — no WikiPage exists at project or group scope; GitLab answers `[]` at 200 for the wiki list and its own 404 for a slug that names nothing. THE SLUG/PAGE-ID HALF: no slug and no wiki_page_meta_id resolves, so GitLab's own 404 is the whole answer — a 200 `[]` on a wiki page's note list would assert that the page exists and nobody commented on it. UNGATED: canon has no WikiPage in any generation. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Wikis" }
      - { method: "GET", path: "/api/v4/hooks", area: "hooks-config", tier: 2, status: "deferred", mode: "refuse", mode_reason: "instance-wide system hooks are admin-only and describe the installation, not the org", mode_reviewed: "2026-09-01", tag: "Hooks" }
      - { method: "GET", path: "/api/v4/hooks/{hook_id}", area: "hooks-config", tier: 2, status: "deferred", mode: "refuse", mode_reason: "instance-wide system hooks are admin-only and describe the installation, not the org", mode_reviewed: "2026-09-01", tag: "Hooks" }
      - { method: "GET", path: "/api/v4/integrations/jira_forge/subscriptions", area: "jira forge subscriptions", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Integration; this universe literally has a Jira and a Slack to be integrated with", mode_reviewed: "2026-09-01", tag: "Jira forge subscriptions", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/internal/agents/agentw/agent_info", area: "workspaces", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the /api/v4/internal/* family is GitLab-to-Gitaly/agent plumbing outside the public API contract; no client library calls it", mode_reviewed: "2026-09-01", tag: "Workspaces", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/internal/agents/agentw/authorize_user_access", area: "workspaces", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the /api/v4/internal/* family is GitLab-to-Gitaly/agent plumbing outside the public API contract; no client library calls it", mode_reviewed: "2026-09-01", tag: "Workspaces", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/internal/agents/agentw/server_config", area: "oauth applications", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the /api/v4/internal/* family is GitLab-to-Gitaly/agent plumbing outside the public API contract; no client library calls it", mode_reviewed: "2026-09-01", tag: "OAuth applications", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/internal/gitaly/object_pool_members", area: "<none>", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the /api/v4/internal/* family is GitLab-to-Gitaly/agent plumbing outside the public API contract; no client library calls it", mode_reviewed: "2026-09-01", tag: "<none>", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/issues", area: "issues", tier: 1, status: "deviation", mode: "derive", mode_reviewed: "2026-09-01", tag: "Issues" }
      - { method: "GET", path: "/api/v4/issues_statistics", area: "issues", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Issues" }
      - { method: "GET", path: "/api/v4/issues/{id}", area: "issues", tier: 1, status: "deviation", mode: "derive", mode_reviewed: "2026-09-01", tag: "Issues" }
      - { method: "GET", path: "/api/v4/job", area: "jobs", tier: 2, status: "deferred", mode: "refuse", mode_reason: "these answer a running runner presenting a CI job token, not an API caller; a frozen universe has no live job", mode_reviewed: "2026-09-01", tag: "CI jobs" }
      - { method: "GET", path: "/api/v4/job/allowed_agents", area: "agents", tier: 3, status: "deferred", mode: "refuse", mode_reason: "these answer a running runner presenting a CI job token, not an API caller; a frozen universe has no live job", mode_reviewed: "2026-09-01", tag: "Agents", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/jobs/{id}/artifacts", area: "jobs", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W7): the zip of the files the job uploaded, from `reader.jobArtifacts(job)` + `reader.artifactContent()` - the SAME bytes the Buildkite artifact download and GitHub's `actions/artifacts/{id}/zip` serve for the same canonical job (invariant #5), each member named by `ArtifactRow.path`, which is where the job wrote it. Served INLINE at 200 rather than through GitHub's 302: the vendored document declares `'200': OK` and real GitLab streams the file from the API host through workhorse, so a redirect here would be mirroring the other provider. `Content-Disposition: attachment; filename=\"artifacts.zip\"`, which is the name GitLab stores and serves a job's uploaded archive under. A pre-hello-15 snapshot answers the NAMED generation gap (`ArtifactRow.content` ships with `features.ciConfig`) and not a bare 404, which would say this job uploaded nothing - a claim about the job, and a false one. A job that really has no artifacts still gets GitLab's own `404 Not found`.. THE INSTANCE-SCOPED ADDRESS of that same archive, asserted byte-identical to the project-scoped one. Unlike `/api/v4/job` and `/api/v4/job/allowed_agents` - which are `refuse` because they ask what job the CALLER is running right now, and a frozen universe has no live job - this one names a job by id, and the job it names is one this host serves. Unblocked by the tar/zip writers moving out of packages/renderer-github into `@sandboxapis/archive`, founder-ordered 2026-09-09", mode_reviewed: "2026-09-12", tag: "Jobs" }
      - { method: "GET", path: "/api/v4/jobs/{id}/sbom_scans/{sbom_digest}", area: "software composition analysis", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no SecurityFinding/SbomComponent/Attestation; a scanning org has findings", mode_reviewed: "2026-09-01", tag: "Software composition analysis", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/keys", area: "deploy-keys-tokens", tier: 3, status: "deferred", mode: "refuse", mode_reason: "listing every key, deploy token or impersonation token across the instance requires admin on GitLab; answering would be inventing an admin session", mode_reviewed: "2026-09-01", tag: "Keys" }
      - { method: "GET", path: "/api/v4/keys/{id}", area: "deploy-keys-tokens", tier: 3, status: "deferred", mode: "refuse", mode_reason: "listing every key, deploy token or impersonation token across the instance requires admin on GitLab; answering would be inventing an admin session", mode_reviewed: "2026-09-01", tag: "Keys" }
      - { method: "GET", path: "/api/v4/ldap/{provider}/groups", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "LDAP", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/ldap/groups", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "LDAP", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/license", area: "licenses", tier: 3, status: "deferred", mode: "refuse", mode_reason: "a self-managed license does not exist on a SaaS-shaped mirror and GitLab refuses these to non-admins; managed_licenses is the removed License-Compliance feature", mode_reviewed: "2026-09-01", tag: "Licenses", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/license/{id}", area: "licenses", tier: 3, status: "deferred", mode: "refuse", mode_reason: "a self-managed license does not exist on a SaaS-shaped mirror and GitLab refuses these to non-admins; managed_licenses is the removed License-Compliance feature", mode_reviewed: "2026-09-01", tag: "Licenses", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/license/usage_export", area: "licenses", tier: 3, status: "deferred", mode: "refuse", mode_reason: "a self-managed license does not exist on a SaaS-shaped mirror and GitLab refuses these to non-admins; managed_licenses is the removed License-Compliance feature", mode_reviewed: "2026-09-01", tag: "Licenses", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/licenses", area: "licenses", tier: 3, status: "deferred", mode: "refuse", mode_reason: "this replica mirrors a SaaS-shaped GitLab and holds no instance subscription of its own; GitLab's own 403 for a non-admin token on the licensing surface is the whole answer. THE OLD REASON MISFILED THE ROW: /api/v4/licenses is not the licence TEMPLATE catalog — its 200 is APIEntitiesGitlabLicense (plan, licensee, add_ons, overage, user_limit, historical_max), the same object /api/v4/license and /api/v4/license/{id} return, and both of those have been armed `refuse` at 403 since class 11 of the 2026-09-01 wave. The template catalog is /api/v4/templates/licenses, which this host has served green off license_catalog since wave W8 and which conformance asserts is untouched by this ruling. So this is class 11's own sentence applied to the plural path, and it takes class 11's status. UNGATED: no generation of this universe holds an instance subscription. RULED by the founder 2026-09-12 (round 20)", mode_reviewed: "2026-09-12", tag: "Licenses", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/mcp", area: "mcp", tier: 3, status: "deferred", mode: "refuse", mode_reason: "/api/v4/mcp is a JSON-RPC/SSE agent channel, not a read of org data; SandboxAPIs serves its own MCP server and two tool surfaces would conflict", mode_reviewed: "2026-09-01", tag: "MCP", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/member_roles", area: "member roles", tier: 3, status: "deferred", mode: "refuse", mode_reason: "instance-level custom roles are a self-managed admin surface; GitLab.com answers 404 for them", mode_reviewed: "2026-09-01", tag: "Member roles", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/merge_requests", area: "merge-requests", tier: 1, status: "deviation", mode: "derive", mode_reviewed: "2026-09-01", tag: "Merge requests" }
      - { method: "GET", path: "/api/v4/metadata", area: "instance-admin", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W8): `/api/v4/version` plus the two facts GitLab's Metadata object adds, and all of them are facts about THIS REPLICA rather than about olympus-labs — so the row needs no artifact read and no generation gate. `version` and `revision` come from GITLAB_METADATA in packages/renderer-gitlab/src/ids.ts, the same constant `/api/v4/version` reads, and conformance asserts the two endpoints agree. `kas.enabled` is FALSE because this host runs no Kubernetes agent server — `/projects/{id}/cluster_agents` is classified `generate` for exactly that reason — and the three fields GitLab renders off that server's own configuration are omitted rather than nulled. `enterprise` is TRUE and it is checkable rather than decorative: this host serves `/groups/{id}/epics`, `/groups/{id}/iterations` and `/projects/{id}/approval_rules`, every one of them EE-only, and conformance drives one of them to prove it", mode_reviewed: "2026-09-12", tag: "Metadata", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/namespaces", area: "namespaces", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Namespaces", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/namespaces/{id}", area: "namespaces", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Namespaces", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/namespaces/{id}/exists", area: "namespaces", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Namespaces", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/namespaces/{id}/gitlab_subscription", area: "namespaces", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Subscription/BillingPeriod; decision 7 of 2026-08-29 puts billing in scope with sandbox-issued ids", mode_reviewed: "2026-09-01", tag: "Namespaces", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/namespaces/{id}/subscription_add_on_purchase/{add_on_name}", area: "add on purchases", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Subscription/BillingPeriod; decision 7 of 2026-08-29 puts billing in scope with sandbox-issued ids", mode_reviewed: "2026-09-01", tag: "Add on purchases", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/namespaces/storage/limit_exclusions", area: "namespaces", tier: 3, status: "deferred", mode: "refuse", mode_reason: "namespace storage-limit exclusions are a GitLab Inc. internal admin surface", mode_reviewed: "2026-09-01", tag: "Namespaces", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/notification_settings", area: "notification settings", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no NotificationSetting for a persona", mode_reviewed: "2026-09-01", tag: "Notification settings", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/occurrences/vulnerabilities", area: "dependency management", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no SecurityFinding/SbomComponent/Attestation; a scanning org has findings", mode_reviewed: "2026-09-01", tag: "Dependency management", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/offline_exports", area: "offline transfers", tier: 3, status: "deferred", mode: "refuse", mode_reason: "each of these reads reports on an export or import that a WRITE would have started, and writes are refused; GitLab answers 404 for an export nobody requested", mode_reviewed: "2026-09-01", tag: "Offline transfers", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/offline_exports/{id}", area: "offline transfers", tier: 3, status: "deferred", mode: "refuse", mode_reason: "each of these reads reports on an export or import that a WRITE would have started, and writes are refused; GitLab answers 404 for an export nobody requested", mode_reviewed: "2026-09-01", tag: "Offline transfers", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/packages/conan/v1/conans/{package_name}/{package_version}/{package_username}/{package_channel}", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/packages/conan/v1/conans/{package_name}/{package_version}/{package_username}/{package_channel}/digest", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/packages/conan/v1/conans/{package_name}/{package_version}/{package_username}/{package_channel}/download_urls", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/packages/conan/v1/conans/{package_name}/{package_version}/{package_username}/{package_channel}/packages/{conan_package_reference}", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/packages/conan/v1/conans/{package_name}/{package_version}/{package_username}/{package_channel}/packages/{conan_package_reference}/digest", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/packages/conan/v1/conans/{package_name}/{package_version}/{package_username}/{package_channel}/packages/{conan_package_reference}/download_urls", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/packages/conan/v1/conans/{package_name}/{package_version}/{package_username}/{package_channel}/search", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/packages/conan/v1/conans/search", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/packages/conan/v1/files/{package_name}/{package_version}/{package_username}/{package_channel}/{recipe_revision}/export/{file_name}", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/packages/conan/v1/files/{package_name}/{package_version}/{package_username}/{package_channel}/{recipe_revision}/package/{conan_package_reference}/{package_revision}/{file_name}", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/packages/conan/v1/ping", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/packages/conan/v1/users/authenticate", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/packages/conan/v1/users/check_credentials", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/packages/terraform/modules/v1/{module_namespace}/{module_name}/{module_system}", area: "terraform", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Terraform", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/packages/terraform/modules/v1/{module_namespace}/{module_name}/{module_system}/download", area: "terraform", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Terraform", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/packages/terraform/modules/v1/{module_namespace}/{module_name}/{module_system}/versions", area: "terraform", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Terraform", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/pages/domains", area: "gitlab pages", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the instance-wide Pages domain list is an administrator surface", mode_reviewed: "2026-09-01", tag: "GitLab Pages", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/personal_access_tokens", area: "deploy-keys-tokens", tier: 3, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-10 (hello-16): reader.credentialsForPerson(athena, \"personal-token\") (reader.ts:3075) — \"all personal access tokens accessible by the authenticated user\", which on a NON-ADMINISTRATOR is their own, and athena is who GET /user reports. A TOKEN IS METADATA AND NEVER A VALUE: name, scopes, creation, expiry, last use and state, because a provider shows a token's value once at creation and there is no creation here (the PagerDuty routing-key rule). Canon's neutral TokenScopes map to GitLab's coarser vocabulary in one place (render-credentials.ts) and the mapper THROWS on a scope it has never heard of rather than dropping it. `expires_at` is GitLab's DATE form — its own docs example is \"2021-01-31\" while created_at/last_used_at beside it are timestamps — which the vendored document mistypes date-time, so the row is a deviation. `last_used_ips` is omitted: an IP means something outside this universe and canon records none. Gated on hasCredentials()", mode_reviewed: "2026-09-10", tag: "Access tokens" }
      - { method: "GET", path: "/api/v4/personal_access_tokens/{id}", area: "deploy-keys-tokens", tier: 3, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-10 (hello-16): the caller's own tokens by id, byte-identical to the list's first row. Another member's token id answers GitLab's 404 — the same non-administrator visibility the list reports, read from the other end, and conformance drives it", mode_reviewed: "2026-09-10", tag: "Access tokens" }
      - { method: "GET", path: "/api/v4/personal_access_tokens/self", area: "deploy-keys-tokens", tier: 3, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): `self` names the token the REQUEST AUTHENTICATED WITH, and hello-17 gives the caller one that works: the founding member holds a personal token by construction and the setup-token rotation keeps it live, so the row answers an ACTIVE token rather than the expired one that would have described a request GitLab would have answered 401. The PENDING request canon also carries can never surface here - credentialScope() excludes state='pending' from every list accessor, and credentialRequests() is the only place a request is reachable", mode_reviewed: "2026-09-12", tag: "Access tokens" }
      - { method: "GET", path: "/api/v4/personal_access_tokens/self/associations", area: "deploy-keys-tokens", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): the groups and projects the caller's token reaches, derived from the caller's own membership rows and the projects this organization owns; access_level is their DIRECT standing where they hold one and their organization standing otherwise, which is GitLab's inheritance rule. THE VENDORED DOCUMENT POINTS THIS OPERATION'S 200 AT APIEntitiesPersonalAccessToken - the token, not its associations - contradicting its own summary and description; invariant #2 mirrors the provider, so the body is {groups, projects} and the permissive vendored schema validates it anyway. Paged as ONE sequence, groups first, then split back into the two keys", mode_reviewed: "2026-09-12", tag: "Access tokens" }
      - { method: "GET", path: "/api/v4/project_aliases", area: "project alias", tier: 3, status: "deferred", mode: "refuse", mode_reason: "project aliases exist only to redirect an in-flight GitHub-import mirror and are admin-only", mode_reviewed: "2026-09-01", tag: "Project alias", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/project_aliases/{name}", area: "project alias", tier: 3, status: "deferred", mode: "refuse", mode_reason: "project aliases exist only to redirect an in-flight GitHub-import mirror and are admin-only", mode_reviewed: "2026-09-01", tag: "Project alias", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/project_repository_storage_moves", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Storage moves", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/project_repository_storage_moves/{repository_storage_move_id}", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Storage moves", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects", area: "projects", tier: 1, status: "green", mode: "derive", tag: "Projects" }
      - { method: "GET", path: "/api/v4/projects/{id}", area: "projects", tier: 1, status: "green", mode: "derive", tag: "Projects" }
      - { method: "GET", path: "/api/v4/projects/{id}/(-/)search", area: "search", tier: 2, status: "deviation", mode: "derive", tag: "Search" }
      - { method: "GET", path: "/api/v4/projects/{id}/(-/)search/semantic", area: "search", tier: 2, status: "deferred", mode: "refuse", mode_reason: "GitLab restricts semantic search to Duo Enterprise with an embeddings index built over the repository, and olympus-labs holds no Duo subscription — GitLab's own 403 for an unlicensed namespace is the whole answer. 403 RATHER THAN 404, and the status is the ruling: the vendored operation declares both, and the one that matches the condition the reason names is the plan refusal — the project resolves and the caller may read it, what is missing is the subscription. TWO ROUTES, ONE ROW: the manifest template embeds GitLab's dashed and undashed spellings, exactly as /api/v4/projects/{id}/(-/)search does, and both carry the same x-sandboxapis-refusal row key. UNGATED: no generation of this universe holds a Duo subscription or an embeddings index. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Search" }
      - { method: "GET", path: "/api/v4/projects/{id}/access_requests", area: "access requests", tier: 3, status: "green", mode: "empty", mode_reason: "the project-scoped twin of the group access-request list, held to the same fact: membership is granted directly, so nothing is pending", mode_reviewed: "2026-09-01", tag: "Access requests", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/access_tokens", area: "deploy-keys-tokens", tier: 3, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-10 (hello-16): reader.listCredentials(\"project-token\") filtered on scope_ref (reader.ts:3085) — TWO ROWS, AND THEY ARE THE ROTATION: the CI token in force when the incident opened was revoked at the incident's first instant and a replacement minted in the same breath, so the revoked row's ended_epoch IS the active row's created_epoch (conformance asserts they abut). `user_id` is the principal the token acts as — this universe's CI identity, a person a client can then fetch, where real GitLab mints a bot user. `access_level` is that holder's OWN standing in the repository, read off reader.membershipFor(\"repo\", …) and mapped once by GITLAB_ACCESS_LEVEL: GitLab's own rule is that a resource token cannot exceed its creator's role. Unpaginated, because the vendored operation declares neither page nor per_page. Gated on hasCredentials()", mode_reviewed: "2026-09-10", tag: "Access tokens" }
      - { method: "GET", path: "/api/v4/projects/{id}/access_tokens/{token_id}", area: "deploy-keys-tokens", tier: 3, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-10 (hello-16): the same two rows by id, byte-identical to the list's first entry. A DEPLOY token's id does NOT resolve here and conformance asserts it — GitLab keeps the two families in separate tables and so does canon", mode_reviewed: "2026-09-10", tag: "Access tokens" }
      - { method: "GET", path: "/api/v4/projects/{id}/alert_management_alerts/{alert_iid}/metric_images", area: "alert management", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-18): APIEntitiesMetricImage over the picture the responder took of each alert the incident opened — one screenshot-svg per alert, dated to the moment the series fell back under the threshold, because a picture of a breach is taken once the breach has a shape. WHICH PROJECT AN ALERT BELONGS TO IS DERIVED rather than assumed from there being one: an alert names the incident it opened, an incident names the issue the git canon filed, and that issue names its project — so an alert that opened no incident belongs to no project and is addressable nowhere, which is the truthful answer rather than a default. `alert_iid` is its 1-based position in that project's own alert list, in listAlerts() id order: mint order, therefore never renumbered, the same rule the merge-request and issue iid sequences follow. `file_path` is GitLab's own system-store template with this file's id and name in it — the vendored component's own example path — so it is reproducible rather than decorative; `url` and `url_text` are OMITTED because they are the dashboard link a responder typed beside the image and canon records none. Conformance asserts every image is an image by its content type, that none predates the alert it pictures, and that an alert iid nobody has is GitLab's own 404. Gated on hasAttachmentParents()", mode_reviewed: "2026-09-12", tag: "Alert management", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/analytics/deployment_frequency", area: "analytics", tier: 3, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W8): DORA's PREDECESSOR on this host, and a different shape — `{value, from, to}` per bucket rather than `{date, value}` — folded over the same reader.listDeployments rows, with `environment` and `from` both required as the vendored operation declares. `value` is a `deviation`: the component types it `string` while real GitLab sends the integer count. The clock is the artifact's anchor, for the reason the DORA rows give", mode_reviewed: "2026-09-12", tag: "Analytics", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/approval_rules", area: "merge-requests", tier: 1, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): features.reviewPolicy gives the repository the rule its merges were actually held to - approvals_required MEASURED off the merged pulls, approvers derived from the people the review log records approving. rule_type is `regular` by GitLab's own definition (a rule that names its approvers), eligible_approvers IS users because `groups` is empty, and `groups` is empty as a fact about GITLAB'S MODEL rather than about the policy: canon's approver TEAMS have no GitLab container on this host, which publishes exactly two groups and neither is a team. applies_to_all_protected_branches is true because canon's rule carries no branch filter; the vendored component types the accompanying protected_branches as a single object where real GitLab sends an array, so the row is a deviation", mode_reviewed: "2026-09-12", tag: "Approval rules" }
      - { method: "GET", path: "/api/v4/projects/{id}/approval_rules/{approval_rule_id}", area: "merge-requests", tier: 1, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): the by-id twin of the project's approval-rule list, byte-identical to the same rule inside it", mode_reviewed: "2026-09-12", tag: "Approval rules" }
      - { method: "GET", path: "/api/v4/projects/{id}/approval_settings", area: "merge-requests", tier: 1, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): the private settings surface over the same rule, rendered by the same shaper as /approval_rules so the two cannot drift. fallback_approvals_required is the rule's own number because canon carries ONE approval measurement for a repository - what its merges actually carried - and there is no second figure for a fallback to differ by. `target_branch` narrows nothing and is answered rather than refused, because the rule applies to every protected branch. The vendored component types `rules` as a single object where real GitLab sends an array, so the row is a deviation", mode_reviewed: "2026-09-12", tag: "Approval rules" }
      - { method: "GET", path: "/api/v4/projects/{id}/approvals", area: "merge-requests", tier: 1, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): the project's approval configuration: approvals_before_merge is the rule's own requirement and disable_overriding_approvers_per_merge_request is canon's `optional` read from the other end. `approvers` and `approver_groups` are the empty arrays real GitLab sends on any instance that uses approval RULES, which this one does - not a gap - and the vendored components type both as single objects, so the row is a deviation. The seven policy toggles beside them (reset-on-push, author approval, committer approval, password to approve) are OMITTED rather than defaulted: canon models no such policy and a chosen false would be a placeholder wearing a boolean's clothes", mode_reviewed: "2026-09-12", tag: "Project approvals" }
      - { method: "GET", path: "/api/v4/projects/{id}/attestations/{attestation_iid}/download", area: "attestations", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no SecurityFinding/SbomComponent/Attestation; a scanning org has findings", mode_reviewed: "2026-09-01", tag: "Attestations", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/attestations/{subject_digest}", area: "attestations", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no SecurityFinding/SbomComponent/Attestation; a scanning org has findings", mode_reviewed: "2026-09-01", tag: "Attestations", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/audit_events", area: "projects", tier: 1, status: "planned", mode: "generate", mode_reason: "A WIDENING, NOT A BUILD: canon.AdminAuditEvent exists (packages/canon/src/support-desk.ts:690) and its own doc comment calls it \"GENERIC by construction\". The action vocabulary (AuditAction, :602), the change vocabulary (AuditChangeSlot, :633), the target vocabulary (AuditTargetKind, :611) and the RFC 5737 source-address rule (AuditSourceBlock, :652) all shipped, and Zendesk serves the table today (reader.listAuditEvents(), ruled 2026-09-07). TWO things are missing and neither is the entity: git-host members on AuditTargetKind, and a generation that WRITES personActor — the field is declared for exactly this wave and \"this generation writes none\" (:695-697)", mode_reviewed: "2026-09-09", tag: "Projects" }
      - { method: "GET", path: "/api/v4/projects/{id}/audit_events/{audit_event_id}", area: "projects", tier: 1, status: "planned", mode: "generate", mode_reason: "A WIDENING, NOT A BUILD: canon.AdminAuditEvent exists (packages/canon/src/support-desk.ts:690) and its own doc comment calls it \"GENERIC by construction\". The action vocabulary (AuditAction, :602), the change vocabulary (AuditChangeSlot, :633), the target vocabulary (AuditTargetKind, :611) and the RFC 5737 source-address rule (AuditSourceBlock, :652) all shipped, and Zendesk serves the table today (reader.listAuditEvents(), ruled 2026-09-07). TWO things are missing and neither is the entity: git-host members on AuditTargetKind, and a generation that WRITES personActor — the field is declared for exactly this wave and \"this generation writes none\" (:695-697)", mode_reviewed: "2026-09-09", tag: "Projects" }
      - { method: "GET", path: "/api/v4/projects/{id}/avatar", area: "avatars", tier: 3, status: "green", mode: "derive", mode_reason: "OrgAvatar is canon as of hello-15 (features.orgAvatars): one identicon per repository, subjectKind \"repo\". orgAvatar(\"repo\", ...) answers it and shapeProject's new avatar_url names the /uploads/-/system/project/avatar/{id}/avatar.png path that serves the same bytes", mode_reviewed: "2026-09-07", tag: "Avatars", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/badges", area: "badges", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Badge; project READMEs in this universe carry pipeline and coverage badges", mode_reviewed: "2026-09-01", tag: "Badges", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/badges/{badge_id}", area: "badges", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Badge; project READMEs in this universe carry pipeline and coverage badges", mode_reviewed: "2026-09-01", tag: "Badges", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/badges/render", area: "badges", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Badge; project READMEs in this universe carry pipeline and coverage badges", mode_reviewed: "2026-09-01", tag: "Badges", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/boards", area: "boards", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has sprint/epic/workflow state but no Board; the board layout itself must be generated", mode_reviewed: "2026-09-01", tag: "Boards", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/boards/{board_id}", area: "boards", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has sprint/epic/workflow state but no Board; the board layout itself must be generated", mode_reviewed: "2026-09-01", tag: "Boards", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/boards/{board_id}/lists", area: "boards", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has sprint/epic/workflow state but no Board; the board layout itself must be generated", mode_reviewed: "2026-09-01", tag: "Boards", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/boards/{board_id}/lists/{list_id}", area: "boards", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has sprint/epic/workflow state but no Board; the board layout itself must be generated", mode_reviewed: "2026-09-01", tag: "Boards", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/ci/lint", area: "ci lint", tier: 3, status: "green", mode: "empty", mode_reason: "the parthenon repository has no `.gitlab-ci.yml` — its pipelines are defined in `.circleci/` (ci_config_document, 3 rows, all under .circleci/) and `.github/workflows/`, and no tree entry names a GitLab CI file; GitLab's own answer for a project with no config is a 200 carrying `valid: false` and its own \"Please provide content of .gitlab-ci.yml\" error. NOT A COLLECTION: the operation returns `APIEntitiesCiLintResult`, an object, so the honest empty is GitLab's own failed lint rather than `[]`. `merged_yaml`, `includes` and `jobs` are OMITTED rather than nulled — there is no configuration to merge, nothing to include and no job to describe, all three are optional in the vendored component, and a null typed `string` would buy a deviation for nothing. UNGATED: no generation of this repository's tree carries a `.gitlab-ci.yml`. Falsifiable: the `expectsEmpty` conformance entry (`ciLintEmptyErrors`) names every field and reds the row the day one appears. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "CI lint", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/cluster_agents", area: "cluster agents", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has deployments but no ClusterAgent that performed them", mode_reviewed: "2026-09-01", tag: "Cluster agents", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/cluster_agents/{agent_id}", area: "cluster agents", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has deployments but no ClusterAgent that performed them", mode_reviewed: "2026-09-01", tag: "Cluster agents", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/cluster_agents/{agent_id}/tokens", area: "cluster agents", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has deployments but no ClusterAgent that performed them", mode_reviewed: "2026-09-01", tag: "Cluster agents", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/cluster_agents/{agent_id}/tokens/{token_id}", area: "cluster agents", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has deployments but no ClusterAgent that performed them", mode_reviewed: "2026-09-01", tag: "Cluster agents", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/cluster_agents/{agent_id}/url_configurations", area: "cluster agents", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has deployments but no ClusterAgent that performed them", mode_reviewed: "2026-09-01", tag: "Cluster agents", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/cluster_agents/{agent_id}/url_configurations/{url_configuration_id}", area: "cluster agents", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has deployments but no ClusterAgent that performed them", mode_reviewed: "2026-09-01", tag: "Cluster agents", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/clusters", area: "clusters", tier: 3, status: "deferred", mode: "refuse", mode_reason: "certificate-based cluster integration is disabled on GitLab.com and removed upstream; mirroring it would advertise a surface no current client can reach", mode_reviewed: "2026-09-01", tag: "Clusters", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/clusters/{cluster_id}", area: "clusters", tier: 3, status: "deferred", mode: "refuse", mode_reason: "certificate-based cluster integration is disabled on GitLab.com and removed upstream; mirroring it would advertise a surface no current client can reach", mode_reviewed: "2026-09-01", tag: "Clusters", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/custom_attributes", area: "custom attributes", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab restricts custom attributes to instance administrators; a non-admin token gets 403", mode_reviewed: "2026-09-01", tag: "Custom attributes", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/custom_attributes/{key}", area: "custom attributes", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab restricts custom attributes to instance administrators; a non-admin token gets 403", mode_reviewed: "2026-09-01", tag: "Custom attributes", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/debian_distributions", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Debian" }
      - { method: "GET", path: "/api/v4/projects/{id}/debian_distributions/{codename}", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Debian" }
      - { method: "GET", path: "/api/v4/projects/{id}/debian_distributions/{codename}/key.asc", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Debian" }
      - { method: "GET", path: "/api/v4/projects/{id}/dependencies", area: "dependency management", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no SecurityFinding/SbomComponent/Attestation; a scanning org has findings", mode_reviewed: "2026-09-01", tag: "Dependency management", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/deploy_keys", area: "deploy-keys-tokens", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W8) (hello-15 `ciConfig`): canon.CheckoutKey IS a deploy key — `CheckoutKeyType` is literally \"deploy-key\" — and reader.listCheckoutKeys(repo) already carries the OpenSSH line and BOTH fingerprints in the forms GitLab prints them. `title` is the comment at the end of that same line, READ OFF the material rather than kept as a second copy, so the title and the key can never name two different things; `created_at` is created_epoch; `fingerprint` is the colon-hex MD5 and `fingerprint_sha256` the OpenSSH form. `expires_at`, `last_used_at` and `usage_type` are OMITTED rather than nulled: this universe issues no key with an expiry, records no use of one and stores no usage flag, all three are optional, and a null typed `string` would buy a deviation for nothing. GENERATION-GATED: an artifact without the CI-configuration domain answers that gap rather than `[]`, because `[]` would say this project's CI clones with nothing. `can_push` is FALSE and it is a fact rather than a default: a checkout key exists so CI can CLONE, and nothing in this universe pushes with one. The two `projects_with_*_access` arrays are omitted here, as real GitLab's `Entities::DeployKeysProject` omits them — `can_push` carries the same fact on a project-scoped read", mode_reviewed: "2026-09-12", tag: "Deploy resources" }
      - { method: "GET", path: "/api/v4/projects/{id}/deploy_keys/{key_id}", area: "deploy-keys-tokens", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W8) (hello-15 `ciConfig`): canon.CheckoutKey IS a deploy key — `CheckoutKeyType` is literally \"deploy-key\" — and reader.listCheckoutKeys(repo) already carries the OpenSSH line and BOTH fingerprints in the forms GitLab prints them. `title` is the comment at the end of that same line, READ OFF the material rather than kept as a second copy, so the title and the key can never name two different things; `created_at` is created_epoch; `fingerprint` is the colon-hex MD5 and `fingerprint_sha256` the OpenSSH form. `expires_at`, `last_used_at` and `usage_type` are OMITTED rather than nulled: this universe issues no key with an expiry, records no use of one and stores no usage flag, all three are optional, and a null typed `string` would buy a deviation for nothing. GENERATION-GATED: an artifact without the CI-configuration domain answers that gap rather than `[]`, because `[]` would say this project's CI clones with nothing. The same row by id, byte-identical to the list's entry, which conformance compares directly; a key id nobody holds is GitLab's own 404", mode_reviewed: "2026-09-12", tag: "Deploy resources" }
      - { method: "GET", path: "/api/v4/projects/{id}/deploy_tokens", area: "deploy-keys-tokens", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-10 (hello-16): reader.listCredentials(\"deploy-token\") filtered on scope_ref (reader.ts:3085). `username` is GitLab's OWN derivation, gitlab+deploy-token-{id}, so it is the real value and moves with the id. The scope vocabulary is a DIFFERENT closed set from a PAT's — a deploy token cannot push and cannot reach the API — so canon's scopes map through their own table and it throws on a scope no deploy token can hold. `revoked` and `expired` are read off canon's anchored state and never off a clock, so no Date.now() decides whether a token still works. `expires_at` IS a timestamp here, unlike a personal token's. Gated on hasCredentials()", mode_reviewed: "2026-09-10", tag: "Deploy resources" }
      - { method: "GET", path: "/api/v4/projects/{id}/deploy_tokens/{token_id}", area: "deploy-keys-tokens", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-10 (hello-16): the same row by id, byte-identical to the list's first entry", mode_reviewed: "2026-09-10", tag: "Deploy resources" }
      - { method: "GET", path: "/api/v4/projects/{id}/deployments", area: "deploy-keys-tokens", tier: 3, status: "green", mode: "derive", tag: "Deploy resources" }
      - { method: "GET", path: "/api/v4/projects/{id}/deployments/{deployment_id}", area: "deploy-keys-tokens", tier: 3, status: "green", mode: "derive", tag: "Deploy resources" }
      - { method: "GET", path: "/api/v4/projects/{id}/deployments/{deployment_id}/merge_requests", area: "deploy-keys-tokens", tier: 3, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W8): the deployment names a commit and reader.pullsForCommit resolves the merge requests that commit belongs to — the ones listing it among their commits plus the one whose MERGE commit it is, which is the shape every staging deployment in this universe takes. THE SAME READ backs the DORA lead-time fold, so a lead time and this list cannot disagree about which changes went out. The rows are `glMergeRequest`'s own, carrying the iid `/merge_requests/{iid}` answers to — conformance fetches each one by that iid and asserts it is the same merge request — and the same nullable-key `deviation` the merge-request list already declares. A deployment id nobody has is GitLab's own 404", mode_reviewed: "2026-09-12", tag: "Deploy resources" }
      - { method: "GET", path: "/api/v4/projects/{id}/dora/metrics", area: "dora metrics", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W8): the four DORA metrics folded over reader.listDeployments, listIncidents and pullsForCommit — no new fact, and a caller can recompute every value from `/projects/{id}/deployments` and `/projects/{id}/merge_requests`, which is exactly what conformance does. deployment_frequency counts the successful deployments in the requested environment tiers; lead_time_for_changes is the median of (deployment instant − merge instant) over the merge requests each deployment shipped, reached through the same pullsForCommit read `/deployments/{id}/merge_requests` serves so a lead time and that list cannot disagree; time_to_restore_service is the median of (resolved − opened) over the incidents whose canonical issue belongs to the scope; change_failure_rate is those incidents over those deployments. A MEDIAN OF NOTHING IS NULL, never a zero — a lead time of no time is a different claim from no measurement — while a COUNT of nothing is 0, and conformance drives a window with no deployment to hold that line. THE SHAPE IS PINNED HERE because the vendored document declares NO schema for the 200 at all (`\"200\": {\"description\": \"successful operation\"}` and nothing else): an entry per bucket, `{date, value}`, `date` being the bucket's first UTC day. THE CLOCK IS THE ANCHOR: `end_date` defaults to the artifact's own anchor day and `start_date` to 90 UTC days before it, the same window the group-activity counts use. `metric` is required and its vocabulary is closed; an unknown one is GitLab's own 400 rather than a silently different answer", mode_reviewed: "2026-09-12", tag: "DORA metrics", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/environments", area: "deployments", tier: 2, status: "green", mode: "derive", tag: "Environments" }
      - { method: "GET", path: "/api/v4/projects/{id}/environments/{environment_id}", area: "deployments", tier: 2, status: "green", mode: "derive", tag: "Environments" }
      - { method: "GET", path: "/api/v4/projects/{id}/error_tracking/client_keys", area: "error tracking", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Integration; this universe literally has a Jira and a Slack to be integrated with", mode_reviewed: "2026-09-01", tag: "Error tracking", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/error_tracking/settings", area: "error tracking", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Integration; this universe literally has a Jira and a Slack to be integrated with", mode_reviewed: "2026-09-01", tag: "Error tracking", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/events", area: "events", tier: 2, status: "green", mode: "derive", tag: "Events" }
      - { method: "GET", path: "/api/v4/projects/{id}/export", area: "project import", tier: 3, status: "deferred", mode: "refuse", mode_reason: "each of these reads reports on an export or import that a WRITE would have started, and writes are refused; GitLab answers 404 for an export nobody requested", mode_reviewed: "2026-09-01", tag: "Project import", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/export_relations/download", area: "project import", tier: 3, status: "deferred", mode: "refuse", mode_reason: "each of these reads reports on an export or import that a WRITE would have started, and writes are refused; GitLab answers 404 for an export nobody requested", mode_reviewed: "2026-09-01", tag: "Project import", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/export_relations/status", area: "project import", tier: 3, status: "deferred", mode: "refuse", mode_reason: "each of these reads reports on an export or import that a WRITE would have started, and writes are refused; GitLab answers 404 for an export nobody requested", mode_reviewed: "2026-09-01", tag: "Project import", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/export/download", area: "project import", tier: 3, status: "deferred", mode: "refuse", mode_reason: "each of these reads reports on an export or import that a WRITE would have started, and writes are refused; GitLab answers 404 for an export nobody requested", mode_reviewed: "2026-09-01", tag: "Project import", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/external_status_checks", area: "external status checks", tier: 3, status: "green", mode: "empty", mode_reason: "olympus-labs protects only branches — canon's protected_ref carries two branch patterns at namespace scope and no environment, tag, merge train, push rule or external status check exists; GitLab answers `[]` at 200 for each of these lists and its own 404 for a named one. THE LIST HALF, served as GitLab's empty page with the pagination headers the operation declares. UNGATED: no generation of this universe has ever protected an environment or a tag, queued a merge train, registered an external status check or set a push rule, so every registered pin answers this same `[]`. Falsifiable: the `expectsEmpty` conformance entry reds the row the day canon grows one. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "External status checks", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/feature_flags", area: "feature flags", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no FeatureFlag; a shipping org gates releases behind flags", mode_reviewed: "2026-09-01", tag: "Feature flags", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/feature_flags_user_lists", area: "feature flags", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no FeatureFlag; a shipping org gates releases behind flags", mode_reviewed: "2026-09-01", tag: "Feature flags", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/feature_flags_user_lists/{iid}", area: "feature flags", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no FeatureFlag; a shipping org gates releases behind flags", mode_reviewed: "2026-09-01", tag: "Feature flags", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/feature_flags/{feature_flag_name}", area: "feature flags", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no FeatureFlag; a shipping org gates releases behind flags", mode_reviewed: "2026-09-01", tag: "Feature flags", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/forks", area: "projects", tier: 1, status: "green", mode: "empty", mode_reason: "no project in this universe is a fork and none has been forked: the group owns every project and there is no namespace outside it to fork into — the same fact every project object already reports as forks_count: 0", mode_reviewed: "2026-09-01", tag: "Projects" }
      - { method: "GET", path: "/api/v4/projects/{id}/freeze_periods", area: "freeze periods", tier: 3, status: "green", mode: "empty", mode_reason: "olympus-labs declares no deploy freeze — canon carries no freeze window; GitLab answers `[]` at 200 for a project with none. THE LIST HALF, served as GitLab's empty page with the pagination headers the operation declares. UNGATED: no generation of this universe opens a freeze window, so every registered pin answers this same `[]`. Falsifiable: the `expectsEmpty` conformance entry reds the row the day canon grows one. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Freeze periods", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/freeze_periods/{freeze_period_id}", area: "freeze periods", tier: 3, status: "deferred", mode: "refuse", mode_reason: "olympus-labs declares no deploy freeze — canon carries no freeze window; GitLab answers `[]` at 200 for a project with none. THE NAMED HALF: no name resolves over a collection that is empty, so GitLab's own 404 is the whole answer — `[]` here would assert that the thing exists and holds nothing. UNGATED: no generation of this universe opens a freeze window, so the 404 is true on every artifact. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Freeze periods", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/google_cloud/setup/integrations.sh", area: "project google cloud integration", tier: 3, status: "deferred", mode: "refuse", mode_reason: "these return a shell script that provisions the CALLER's real Google Cloud project; nothing in the response describes the simulated org", mode_reviewed: "2026-09-01", tag: "Project Google Cloud integration", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/google_cloud/setup/runner_deployment_project.sh", area: "project google cloud integration", tier: 3, status: "deferred", mode: "refuse", mode_reason: "these return a shell script that provisions the CALLER's real Google Cloud project; nothing in the response describes the simulated org", mode_reviewed: "2026-09-01", tag: "Project Google Cloud integration", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/groups", area: "projects", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Projects" }
      - { method: "GET", path: "/api/v4/projects/{id}/hooks", area: "hooks-config", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-18): the hooks this project publishes to, off reader.repoWebhooks — hello-18's features.webhookFilters widens canon's webhook_subscription from PagerDuty's three account scopes to the three a repository host publishes at, so a project hook and a group hook are ONE object at two scopes rather than a new entity. THE EVENT NAMES ARE THIS RENDERER'S TRANSLATION, not canon's: canon's WebhookEventKind is neutral (ref.pushed, change.opened, change.merged, issue.opened, issue.closed, build.completed) because three renderers read that table, and GitLab publishes a BOOLEAN PER FAMILY instead of a list of names — so ref.pushed becomes push_events, change.opened and change.merged both become merge_requests_events (GitLab has ONE merge-request flag), issue.opened and issue.closed both become issues_events, and build.completed becomes job_events, whose own payload GitLab spells `object_kind: build`. Every other flag the vendored component declares is FALSE, and conformance asserts that in both directions so a flag cannot start defaulting to true. `alert_status` carries canon's `active`, because APIEntitiesProjectHook has no `active` property at all and `executable`/`disabled` is GitLab's own vocabulary for whether a hook will fire. `token_present` and `signing_token_present` are FALSE and are sent, because canon states there is no secret; the knobs canon does not hold (enable_ssl_verification, url_variables, branch filters, custom templates and headers, organization_id, name) are OMITTED rather than defaulted. Gated on hasWebhookFilters(); an older artifact answers the named hello-18 webhook gap, because [] there would say this organization wires up nothing", mode_reviewed: "2026-09-12", tag: "Hooks" }
      - { method: "GET", path: "/api/v4/projects/{id}/hooks/{hook_id}", area: "hooks-config", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-18): the same hook by id, byte-identical to the row the list publishes — conformance compares them directly. THE ID MUST BELONG TO THIS PROJECT: a hook id from the group's own feed is GitLab's 404 here, which is the same scoping reader.repoWebhooks()/orgWebhooks() enforce one layer down and which conformance drives from both sides. A hook id nobody holds is GitLab's own 404. Gated on hasWebhookFilters()", mode_reviewed: "2026-09-12", tag: "Hooks" }
      - { method: "GET", path: "/api/v4/projects/{id}/hooks/{hook_id}/events", area: "hooks-config", tier: 2, status: "deferred", mode: "generate", mode_reason: "RE-SCOPED 2026-09-12 by the hello-18 webhook wave, which served the four hook rows beside this one. The old reason (\"canon has no Webhook\") is now FALSE: canon carries webhook_subscription with the git hosts' three scopes as of hello-18, and this host serves the subscriptions. What is missing is a DELIVERY LOG — one row per attempted POST, with the request it sent and the response it got — which is a second entity hello-18 deliberately did not invent (decisions/2026-09-12-1125). The subscription's last_delivery_epoch/code/status are a fact about the SUBSCRIPTION, published on the subscription by every host in the fleet, and one row is not a log to page. THE ASK: a canon DeliveryAttempt hanging off webhook_subscription, and this row goes green off it", mode_reviewed: "2026-09-12", tag: "Hooks" }
      - { method: "GET", path: "/api/v4/projects/{id}/import", area: "project import", tier: 3, status: "deferred", mode: "refuse", mode_reason: "each of these reads reports on an export or import that a WRITE would have started, and writes are refused; GitLab answers 404 for an export nobody requested", mode_reviewed: "2026-09-01", tag: "Project import", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/integrations", area: "integrations", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Integration; this universe literally has a Jira and a Slack to be integrated with", mode_reviewed: "2026-09-01", tag: "Integrations", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/integrations/{slug}", area: "integrations", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Integration; this universe literally has a Jira and a Slack to be integrated with", mode_reviewed: "2026-09-01", tag: "Integrations", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/invitations", area: "groups", tier: 1, status: "green", mode: "empty", mode_reason: "no pending repository invitations in this universe — the repository roster is the approvers whose organization role is a plain member, plus the CI identity, and all of them were GRANTED rather than offered; GitLab's own answer for a project with none is `[]` at 200. THE GROUP TWIN IS NOT EMPTY and is served with real rows: hello-16 models an invitation as a pending membership carrying an invitee_email, two org-scope memberships are in exactly that state, and /groups/{id}/invitations has served them since wave W3 — what canon does not carry is a REPOSITORY-scoped pending membership, since reader.listMemberships(\"repo\", repo) holds six rows and every one is active. The same reading the founder made of GitHub's twin /repos/{owner}/{repo}/invitations on 2026-09-10. UNGATED: every repository membership in every generation is granted rather than offered, including the four that predate features.memberships and carry no membership table at all. Falsifiable: the `expectsEmpty` conformance entry reds this row the day the generator offers a repository seat. RULED by the founder 2026-09-12 (round 20)", mode_reviewed: "2026-09-12", tag: "Invitations" }
      - { method: "GET", path: "/api/v4/projects/{id}/invited_groups", area: "projects", tier: 1, status: "green", mode: "empty", mode_reason: "the project-scoped twin of the group invitation list, held to the same fact: a second group exists from hello-16, and no invitation to this project has ever been made. Reviewed again 2026-09-09 against the subgroup.", mode_reviewed: "2026-09-09", tag: "Projects" }
      - { method: "GET", path: "/api/v4/projects/{id}/issues", area: "projects", tier: 1, status: "deviation", mode: "derive", tag: "Projects" }
      - { method: "GET", path: "/api/v4/projects/{id}/issues_statistics", area: "projects", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Projects" }
      - { method: "GET", path: "/api/v4/projects/{id}/issues/{eventable_id}/resource_iteration_events", area: "events", tier: 2, status: "deferred", mode: "generate", mode_reason: "canon keeps current label/milestone state, not its history; needs a ResourceEvent log", mode_reviewed: "2026-09-01", tag: "Resource events" }
      - { method: "GET", path: "/api/v4/projects/{id}/issues/{eventable_id}/resource_iteration_events/{event_id}", area: "events", tier: 2, status: "deferred", mode: "generate", mode_reason: "canon keeps current label/milestone state, not its history; needs a ResourceEvent log", mode_reviewed: "2026-09-01", tag: "Resource events" }
      - { method: "GET", path: "/api/v4/projects/{id}/issues/{eventable_id}/resource_label_events", area: "events", tier: 2, status: "deferred", mode: "generate", mode_reason: "canon keeps current label/milestone state, not its history; needs a ResourceEvent log", mode_reviewed: "2026-09-01", tag: "Resource events" }
      - { method: "GET", path: "/api/v4/projects/{id}/issues/{eventable_id}/resource_label_events/{event_id}", area: "events", tier: 2, status: "deferred", mode: "generate", mode_reason: "canon keeps current label/milestone state, not its history; needs a ResourceEvent log", mode_reviewed: "2026-09-01", tag: "Resource events" }
      - { method: "GET", path: "/api/v4/projects/{id}/issues/{eventable_id}/resource_milestone_events", area: "events", tier: 2, status: "deferred", mode: "generate", mode_reason: "canon keeps current label/milestone state, not its history; needs a ResourceEvent log", mode_reviewed: "2026-09-01", tag: "Resource events" }
      - { method: "GET", path: "/api/v4/projects/{id}/issues/{eventable_id}/resource_milestone_events/{event_id}", area: "events", tier: 2, status: "deferred", mode: "generate", mode_reason: "canon keeps current label/milestone state, not its history; needs a ResourceEvent log", mode_reviewed: "2026-09-01", tag: "Resource events" }
      - { method: "GET", path: "/api/v4/projects/{id}/issues/{eventable_id}/resource_state_events", area: "events", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W8): GitLab's ResourceStateEvent vocabulary is NARROW — opened, closed, merged, reopened — and canon's `issue_transition` is a WORKFLOW-COLUMN log (backlog, todo, in_progress, in_review, done, canceled). So a column move is NOT a state event and is not served as one: only a move into a terminal column (done or canceled, exactly the two workflow states canon marks an issue `closed` in) is a CLOSE, and a move back out of one would be a REOPEN. `wave-w8.test.ts` walks the whole issue roster and asserts that constant against the artifact, so the day canon grows a third terminal column the row goes red rather than quietly under-reporting a close. `id` is (issue, ord) minted through gitlabId; `user` is the transition's actor, `created_at` its instant, and `source_merge_request_id` the merge request that performed the close where `by_pull` records one and nothing at all where it does not. `source_commit` is omitted — canon records no commit against a close. An OPEN issue has no state event and says so with `[]` rather than a 404: the issue resolves, it simply never changed state. An iid nobody has is GitLab's own 404", mode_reviewed: "2026-09-12", tag: "Resource events" }
      - { method: "GET", path: "/api/v4/projects/{id}/issues/{eventable_id}/resource_state_events/{event_id}", area: "events", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W8): GitLab's ResourceStateEvent vocabulary is NARROW — opened, closed, merged, reopened — and canon's `issue_transition` is a WORKFLOW-COLUMN log (backlog, todo, in_progress, in_review, done, canceled). So a column move is NOT a state event and is not served as one: only a move into a terminal column (done or canceled, exactly the two workflow states canon marks an issue `closed` in) is a CLOSE, and a move back out of one would be a REOPEN. `wave-w8.test.ts` walks the whole issue roster and asserts that constant against the artifact, so the day canon grows a third terminal column the row goes red rather than quietly under-reporting a close. `id` is (issue, ord) minted through gitlabId; `user` is the transition's actor, `created_at` its instant, and `source_merge_request_id` the merge request that performed the close where `by_pull` records one and nothing at all where it does not. `source_commit` is omitted — canon records no commit against a close. The same event by id, byte-identical to its entry in the list, which conformance compares directly", mode_reviewed: "2026-09-12", tag: "Resource events" }
      - { method: "GET", path: "/api/v4/projects/{id}/issues/{eventable_id}/resource_weight_events", area: "events", tier: 2, status: "deferred", mode: "generate", mode_reason: "canon keeps current label/milestone state, not its history; needs a ResourceEvent log", mode_reviewed: "2026-09-01", tag: "Resource events" }
      - { method: "GET", path: "/api/v4/projects/{id}/issues/{eventable_id}/resource_weight_events/{event_id}", area: "events", tier: 2, status: "deferred", mode: "generate", mode_reason: "canon keeps current label/milestone state, not its history; needs a ResourceEvent log", mode_reviewed: "2026-09-01", tag: "Resource events" }
      - { method: "GET", path: "/api/v4/projects/{id}/issues/{issue_iid}", area: "projects", tier: 1, status: "deviation", mode: "derive", tag: "Projects" }
      - { method: "GET", path: "/api/v4/projects/{id}/issues/{issue_iid}/award_emoji", area: "award emoji", tier: 3, status: "green", mode: "derive", mode_reason: "ContentReaction is canon as of hello-15 (features.contentReactions): one row per person per gesture per target, with an id, a discriminated target and an instant. reactionsFor() answers it and renderer-gitlab's glAwardEmoji renders GitLab's AwardEmoji envelope over it - the same rows GitHub serves as reactions and Azure DevOps as comment reactions", mode_reviewed: "2026-09-07", tag: "Award emoji", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/issues/{issue_iid}/award_emoji/{award_id}", area: "award emoji", tier: 3, status: "green", mode: "derive", mode_reason: "ContentReaction is canon as of hello-15 (features.contentReactions): one row per person per gesture per target, with an id, a discriminated target and an instant. reactionsFor() answers it and renderer-gitlab's glAwardEmoji renders GitLab's AwardEmoji envelope over it - the same rows GitHub serves as reactions and Azure DevOps as comment reactions", mode_reviewed: "2026-09-07", tag: "Award emoji", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/issues/{issue_iid}/closed_by", area: "projects", tier: 1, status: "deviation", mode: "derive", mode_reviewed: "2026-09-01", tag: "Projects" }
      - { method: "GET", path: "/api/v4/projects/{id}/issues/{issue_iid}/links", area: "issues", tier: 1, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): features.issueLinks derives the edges from the storyline - issues in one storyline relate, and an issue whose close precedes another's start blocks it. Canon stores the link ONCE, directed; this route renders it relative to the issue you asked about, so one `blocks` row reads `blocks` from the blocker's end and `is_blocked_by` from the blocked one's. The other end is the same issue /issues/{iid} serves, shaped by the same glIssue, plus the four link fields APIEntitiesRelatedIssue adds; sorted by the relationship's own instant ascending, which is the vendored document's own ordering. Answers the named hello-17 generation gap on every older artifact", mode_reviewed: "2026-09-12", tag: "Issues" }
      - { method: "GET", path: "/api/v4/projects/{id}/issues/{issue_iid}/links/{issue_link_id}", area: "issues", tier: 1, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): one link by id, naming both ends outright - so link_type here is the CANONICAL direction rather than the relative one /links prints. Looked up inside this issue's own links, so a link between two other issues 404s rather than being served under a parent it does not touch", mode_reviewed: "2026-09-12", tag: "Issues" }
      - { method: "GET", path: "/api/v4/projects/{id}/issues/{issue_iid}/metric_images", area: "metric images", tier: 3, status: "green", mode: "empty", mode_reason: "RE-RULED 2026-09-12 by the founder, replacing the `generate` this row carried since the hello-18 upload wave. THE FACTS DID NOT MOVE, THE VERDICT DID. GitLab scopes this operation to INCIDENTS and this universe HAS incident issues, so the collection is addressable and real; what it holds is nothing. The responder's picture IS in this universe - it is attached to the ALERT, and /projects/{id}/alert_management_alerts/{alert_iid}/metric_images has published it since hello-18 - so rendering the same canonical object under the issue as well would publish one upload twice (invariant #5). The one file canon hangs off the incident issue is a har-summary (requests.har), a capture rather than a picture of a metric. `generate` said the opposite - that the row was waiting on canon - and a row waiting forever for a file nobody would attach is a backlog entry rather than a plan. NO GENERATION GATE, unlike the alert half: `[]` is true on every artifact this fleet has ever published, because no generation has hung an image attachment off the incident issue. Both parents still resolve. RULED by the founder 2026-09-12, reason as given in decisions/2026-09-12-2026-post-h18-serve-pass.md.", mode_reviewed: "2026-09-12", tag: "Metric images", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/issues/{issue_iid}/notes/{note_id}/award_emoji", area: "award emoji", tier: 3, status: "green", mode: "derive", mode_reason: "ContentReaction is canon as of hello-15 (features.contentReactions): one row per person per gesture per target, with an id, a discriminated target and an instant. reactionsFor() answers it and renderer-gitlab's glAwardEmoji renders GitLab's AwardEmoji envelope over it - the same rows GitHub serves as reactions and Azure DevOps as comment reactions", mode_reviewed: "2026-09-07", tag: "Award emoji", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/issues/{issue_iid}/notes/{note_id}/award_emoji/{award_id}", area: "award emoji", tier: 3, status: "green", mode: "derive", mode_reason: "ContentReaction is canon as of hello-15 (features.contentReactions): one row per person per gesture per target, with an id, a discriminated target and an instant. reactionsFor() answers it and renderer-gitlab's glAwardEmoji renders GitLab's AwardEmoji envelope over it - the same rows GitHub serves as reactions and Azure DevOps as comment reactions", mode_reviewed: "2026-09-07", tag: "Award emoji", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/issues/{issue_iid}/participants", area: "issues", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Issues" }
      - { method: "GET", path: "/api/v4/projects/{id}/issues/{issue_iid}/related_merge_requests", area: "issues", tier: 1, status: "deviation", mode: "derive", mode_reviewed: "2026-09-01", tag: "Issues" }
      - { method: "GET", path: "/api/v4/projects/{id}/issues/{issue_iid}/time_stats", area: "issues", tier: 1, status: "deviation", mode: "empty", mode_reason: "no persona in olympus-labs logs time against an issue or a merge request — canon records no TimeEntry; GitLab's own answer for an untracked issue is a 200 carrying `time_estimate: 0`, `total_time_spent: 0` and both human_ fields null. NOT A COLLECTION: the operation returns `APIEntitiesIssuableTimeStats`, an object, so the honest empty is the zeroed object rather than `[]`. It is the SAME object `glIssue` and `glMergeRequest` already embed as `time_stats` (`emptyTimeStats` in packages/renderer-gitlab/src/render2.ts), read from one function so the standalone endpoint and the embedded block can never disagree (invariant #5). canon's `Issue.estimate` is a story-point estimate on a fibonacci scale rather than a duration, and `time_estimate` is documented in seconds, so mapping one onto the other would be an invention. The two human_ fields are a `deviation` against the vendored component, which types them `string` with no `nullable` while real GitLab renders nil for a zero — the same two entries NULLABLE_SPEC_BUGS already carries for the embedded block. UNGATED: no generation of this universe records a time entry. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Issues" }
      - { method: "GET", path: "/api/v4/projects/{id}/issues/{issue_iid}/user_agent_detail", area: "issues", tier: 1, status: "planned", mode: "refuse", mode_reason: "GitLab exposes user-agent detail to instance administrators for abuse reports only; a non-admin token gets 403", mode_reviewed: "2026-09-01", tag: "Issues" }
      - { method: "GET", path: "/api/v4/projects/{id}/issues/{noteable_id}/discussions", area: "discussions", tier: 1, status: "deviation", mode: "derive", mode_reviewed: "2026-09-01", tag: "Discussions" }
      - { method: "GET", path: "/api/v4/projects/{id}/issues/{noteable_id}/discussions/{discussion_id}", area: "discussions", tier: 1, status: "deviation", mode: "derive", mode_reviewed: "2026-09-01", tag: "Discussions" }
      - { method: "GET", path: "/api/v4/projects/{id}/issues/{noteable_id}/discussions/{discussion_id}/notes", area: "discussions", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Discussions" }
      - { method: "GET", path: "/api/v4/projects/{id}/issues/{noteable_id}/discussions/{discussion_id}/notes/{note_id}", area: "discussions", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Discussions" }
      - { method: "GET", path: "/api/v4/projects/{id}/issues/{noteable_id}/notes", area: "notes", tier: 1, status: "green", mode: "derive", tag: "Notes" }
      - { method: "GET", path: "/api/v4/projects/{id}/issues/{noteable_id}/notes/{note_id}", area: "notes", tier: 1, status: "green", mode: "derive", tag: "Notes" }
      - { method: "GET", path: "/api/v4/projects/{id}/iterations", area: "iterations", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W8): a GitLab iteration IS canon's sprint — reader.listSprints() — which is the same object Jira serves as a Sprint and Azure DevOps as an iteration path, so the 27 windows and their dates are one set read three ways (invariant #5). THE iid IS GROUP-WIDE AND `sequence` IS PER-CADENCE, and that is the one decision this mapping makes: `sprint.idx` counts within a TEAM and four teams each run their own series, so `idx` repeats four times over and cannot be an iid GitLab guarantees unique inside a group — an iteration cadence being exactly one team's series, `sequence` IS `sprint.idx` and the iid is the group-wide rank by start date, ties broken by team and then by index so the numbering is total and stable. `state` is GitLab's INTEGER enum (started 2, closed 3); nothing here is ever upcoming, because the generator closes a sprint whose end falls before the window's end and starts none after it. `title` and `description` are OMITTED, and that is GitLab's own shape rather than a gap: iteration titles were removed in GitLab 15.6 and the field has been nullable since. `created_at`/`updated_at` are omitted because canon's sprint carries no instant beyond its start and end. BYTE-IDENTICAL to the group's list, which conformance compares directly: an iteration belongs to the group, and `include_ancestors` — GitLab's own default — is why a project sees them at all. Two different lists would be this host disagreeing with itself about one cadence", mode_reviewed: "2026-09-12", tag: "Iterations", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/job_token_scope", area: "projects job token scope", tier: 3, status: "deferred", mode: "generate", mode_reason: "RE-SCOPED 2026-09-09: the 23-row CiVariable+PipelineSchedule+ResourceGroup+SecureFile+FreezePeriod clique was hiding a solved fifth — hello-15's canon.WorkflowSchedule answers the PIPELINE SCHEDULES (see /api/v4/projects/{id}/pipeline_schedules). A JOB TOKEN is not: the scope rows are the cross-project trust list a CI job's token may reach, and the trigger rows are the tokens that start a pipeline from outside. canon stores no token (the PagerDuty routing-key rule, DECISIONS 2026-09-03) and this universe holds one project, so neither the allowlist nor the trigger has anything to point at. New canon entities JobTokenScope and PipelineTrigger", mode_reviewed: "2026-09-09", tag: "Projects job token scope", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/job_token_scope/allowlist", area: "projects job token scope", tier: 3, status: "deferred", mode: "generate", mode_reason: "RE-SCOPED 2026-09-09: the 23-row CiVariable+PipelineSchedule+ResourceGroup+SecureFile+FreezePeriod clique was hiding a solved fifth — hello-15's canon.WorkflowSchedule answers the PIPELINE SCHEDULES (see /api/v4/projects/{id}/pipeline_schedules). A JOB TOKEN is not: the scope rows are the cross-project trust list a CI job's token may reach, and the trigger rows are the tokens that start a pipeline from outside. canon stores no token (the PagerDuty routing-key rule, DECISIONS 2026-09-03) and this universe holds one project, so neither the allowlist nor the trigger has anything to point at. New canon entities JobTokenScope and PipelineTrigger", mode_reviewed: "2026-09-09", tag: "Projects job token scope", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/job_token_scope/groups_allowlist", area: "projects job token scope", tier: 3, status: "deferred", mode: "generate", mode_reason: "RE-SCOPED 2026-09-09: the 23-row CiVariable+PipelineSchedule+ResourceGroup+SecureFile+FreezePeriod clique was hiding a solved fifth — hello-15's canon.WorkflowSchedule answers the PIPELINE SCHEDULES (see /api/v4/projects/{id}/pipeline_schedules). A JOB TOKEN is not: the scope rows are the cross-project trust list a CI job's token may reach, and the trigger rows are the tokens that start a pipeline from outside. canon stores no token (the PagerDuty routing-key rule, DECISIONS 2026-09-03) and this universe holds one project, so neither the allowlist nor the trigger has anything to point at. New canon entities JobTokenScope and PipelineTrigger", mode_reviewed: "2026-09-09", tag: "Projects job token scope", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/jobs", area: "jobs", tier: 2, status: "green", mode: "derive", tag: "CI jobs" }
      - { method: "GET", path: "/api/v4/projects/{id}/jobs/{job_id}", area: "jobs", tier: 2, status: "green", mode: "derive", tag: "CI jobs" }
      - { method: "GET", path: "/api/v4/projects/{id}/jobs/{job_id}/artifacts", area: "jobs", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W7): the zip of the files the job uploaded, from `reader.jobArtifacts(job)` + `reader.artifactContent()` - the SAME bytes the Buildkite artifact download and GitHub's `actions/artifacts/{id}/zip` serve for the same canonical job (invariant #5), each member named by `ArtifactRow.path`, which is where the job wrote it. Served INLINE at 200 rather than through GitHub's 302: the vendored document declares `'200': OK` and real GitLab streams the file from the API host through workhorse, so a redirect here would be mirroring the other provider. `Content-Disposition: attachment; filename=\"artifacts.zip\"`, which is the name GitLab stores and serves a job's uploaded archive under. A pre-hello-15 snapshot answers the NAMED generation gap (`ArtifactRow.content` ships with `features.ciConfig`) and not a bare 404, which would say this job uploaded nothing - a claim about the job, and a false one. A job that really has no artifacts still gets GitLab's own `404 Not found`. Unblocked by the tar/zip writers moving out of packages/renderer-github into `@sandboxapis/archive`, founder-ordered 2026-09-09", mode_reviewed: "2026-09-12", tag: "Job artifacts" }
      - { method: "GET", path: "/api/v4/projects/{id}/jobs/{job_id}/artifacts/tree", area: "jobs", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W8) (hello-15 `ciConfig`): `artifact.path` is where the job wrote the file relative to the workspace root, so the archive's directory tree is a GROUP-BY over those paths and needs no archive format at all — which is what separates this row from the three artifact DOWNLOAD rows. One entry per directory on the way to a file plus one per file, in path order; `?recursive=` and `?path=` narrow it as the vendored operation declares. `mode` is OMITTED throughout: canon records no POSIX mode for an artifact and \"100644\" would be this renderer inventing one. A JOB WITH NO ARTIFACT IS A 404 rather than an empty list — GitLab's artifact browser has nothing to browse when the job uploaded no archive, and `[]` would advertise an empty archive that does not exist; conformance drives such a job and asserts the 404. Generation-gated: an older artifact has no `artifact.path` column at all", mode_reviewed: "2026-09-12", tag: "Job artifacts" }
      - { method: "GET", path: "/api/v4/projects/{id}/jobs/{job_id}/trace", area: "jobs", tier: 2, status: "green", mode: "derive", mode_reason: "hello-13's JobLog/JobLogLine ARE the job trace: the endpoint serves reader.jobLogText(job) — the same canonical bytes Bitbucket's step log serves for the same job. Per-test-case results are a different surface (jobs/{id}/artifacts/tree) and stay generate", mode_reviewed: "2026-09-02", tag: "CI jobs" }
      - { method: "GET", path: "/api/v4/projects/{id}/jobs/artifacts/{ref_name}/download", area: "jobs", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W7): the zip of the files the job uploaded, from `reader.jobArtifacts(job)` + `reader.artifactContent()` - the SAME bytes the Buildkite artifact download and GitHub's `actions/artifacts/{id}/zip` serve for the same canonical job (invariant #5), each member named by `ArtifactRow.path`, which is where the job wrote it. Served INLINE at 200 rather than through GitHub's 302: the vendored document declares `'200': OK` and real GitLab streams the file from the API host through workhorse, so a redirect here would be mirroring the other provider. `Content-Disposition: attachment; filename=\"artifacts.zip\"`, which is the name GitLab stores and serves a job's uploaded archive under. A pre-hello-15 snapshot answers the NAMED generation gap (`ArtifactRow.content` ships with `features.ciConfig`) and not a bare 404, which would say this job uploaded nothing - a claim about the job, and a false one. A job that really has no artifacts still gets GitLab's own `404 Not found`.. ADDRESSED BY REF AND JOB NAME: the latest successful pipeline on the branch or tag, then the job of that name on it. `ref_name` resolves as a branch or a tag and nothing else, because the document says outright that `HEAD` or `SHA` references are not supported. A missing `job` is Grape's own `{\"error\": \"job is missing\"}` at 400 - that envelope and not GitLab's usual `{message}`, because that is what the framework actually sends for a missing required parameter. `search_recent_successful_pipelines` is refused rather than implemented: it widens the search from the latest successful pipeline to `recent` ones, and neither the vendored document nor GitLab's own page says how far back that reaches, so answering it would be answering a different question. Unblocked by the tar/zip writers moving out of packages/renderer-github into `@sandboxapis/archive`, founder-ordered 2026-09-09", mode_reviewed: "2026-09-12", tag: "Job artifacts" }
      - { method: "GET", path: "/api/v4/projects/{id}/labels", area: "labels", tier: 1, status: "green", mode: "derive", tag: "Labels" }
      - { method: "GET", path: "/api/v4/projects/{id}/labels/{name}", area: "labels", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Labels" }
      - { method: "GET", path: "/api/v4/projects/{id}/languages", area: "projects", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Projects" }
      - { method: "GET", path: "/api/v4/projects/{id}/managed_licenses", area: "licenses", tier: 3, status: "deferred", mode: "refuse", mode_reason: "a self-managed license does not exist on a SaaS-shaped mirror and GitLab refuses these to non-admins; managed_licenses is the removed License-Compliance feature", mode_reviewed: "2026-09-01", tag: "Licenses", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/managed_licenses/{managed_license_id}", area: "licenses", tier: 3, status: "deferred", mode: "refuse", mode_reason: "a self-managed license does not exist on a SaaS-shaped mirror and GitLab refuses these to non-admins; managed_licenses is the removed License-Compliance feature", mode_reviewed: "2026-09-01", tag: "Licenses", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/members", area: "groups", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Members" }
      - { method: "GET", path: "/api/v4/projects/{id}/members/{user_id}", area: "groups", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Members" }
      - { method: "GET", path: "/api/v4/projects/{id}/members/all", area: "groups", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Members" }
      - { method: "GET", path: "/api/v4/projects/{id}/members/all/{user_id}", area: "groups", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Members" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_request_approval_setting", area: "merge-requests", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): one field, and it is the one canon answers: allow_overrides_to_approver_list_per_merge_request IS canon's `optional`, which says whether a rule may be overridden on a single merge request. The other six settings this entity carries are policy toggles canon does not model and are omitted rather than defaulted, the same ruling /projects/{id}/approvals takes", mode_reviewed: "2026-09-12", tag: "Merge request approvals" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests", area: "merge-requests", tier: 1, status: "deviation", mode: "derive", tag: "Merge requests" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{eventable_id}/resource_label_events", area: "events", tier: 2, status: "deferred", mode: "generate", mode_reason: "canon keeps current label/milestone state, not its history; needs a ResourceEvent log", mode_reviewed: "2026-09-01", tag: "Resource events" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{eventable_id}/resource_label_events/{event_id}", area: "events", tier: 2, status: "deferred", mode: "generate", mode_reason: "canon keeps current label/milestone state, not its history; needs a ResourceEvent log", mode_reviewed: "2026-09-01", tag: "Resource events" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{eventable_id}/resource_milestone_events", area: "events", tier: 2, status: "deferred", mode: "generate", mode_reason: "canon keeps current label/milestone state, not its history; needs a ResourceEvent log", mode_reviewed: "2026-09-01", tag: "Resource events" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{eventable_id}/resource_milestone_events/{event_id}", area: "events", tier: 2, status: "deferred", mode: "generate", mode_reason: "canon keeps current label/milestone state, not its history; needs a ResourceEvent log", mode_reviewed: "2026-09-01", tag: "Resource events" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{eventable_id}/resource_state_events", area: "events", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W8): canon needs no history table for a merge request's state — one that settled carries the instant it settled at, and that instant IS the one event GitLab records: `merged` for one that landed, `closed` for one that did not, and nothing for one still open. reader.listPulls; `user` is the author, `resource_id` the merge request, `id` minted from (pull, state). An open merge request answers `[]` rather than a 404: it resolves, it simply has not settled. An iid nobody has is GitLab's own 404", mode_reviewed: "2026-09-12", tag: "Resource events" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{eventable_id}/resource_state_events/{event_id}", area: "events", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W8): canon needs no history table for a merge request's state — one that settled carries the instant it settled at, and that instant IS the one event GitLab records: `merged` for one that landed, `closed` for one that did not, and nothing for one still open. reader.listPulls; `user` is the author, `resource_id` the merge request, `id` minted from (pull, state). The same event by id, byte-identical to its entry in the list", mode_reviewed: "2026-09-12", tag: "Resource events" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{merge_request_iid}", area: "merge-requests", tier: 1, status: "deviation", mode: "derive", tag: "Merge requests" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{merge_request_iid}/approval_rules", area: "merge-requests", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): the project's rule as one merge request sees it. source_rule reports the project rule's requirement and `overridden` is read off canon's `optional` rather than hard-coded - nothing in this universe writes a per-merge-request rule, and a rule canon marks non-overridable cannot have been overridden", mode_reviewed: "2026-09-12", tag: "Merge request approvals" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{merge_request_iid}/approval_rules/{approval_rule_id}", area: "merge-requests", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): the by-id twin of the merge request's approval-rule list, byte-identical to the same rule inside it", mode_reviewed: "2026-09-12", tag: "Merge request approvals" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{merge_request_iid}/approval_state", area: "merge-requests", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): how far along one merge request is: approved_by is MEASURED from the reviewers whose verdict was `approve` - the same review table canon derived the rule's approver list from - and `approved` is the arithmetic of approved_by against approvals_required, so a client can recompute it from the two fields printed beside it. Every approver is checked to be an eligible one, and /merge_requests/{iid}/approvals (green since the depth wave) now reads approvals_required off the same rule so the two surfaces cannot disagree", mode_reviewed: "2026-09-12", tag: "Merge request approvals" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{merge_request_iid}/approvals", area: "merge-requests", tier: 1, status: "green", mode: "derive", tag: "Merge request approvals" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{merge_request_iid}/award_emoji", area: "award emoji", tier: 3, status: "green", mode: "derive", mode_reason: "ContentReaction is canon as of hello-15 (features.contentReactions): one row per person per gesture per target, with an id, a discriminated target and an instant. reactionsFor() answers it and renderer-gitlab's glAwardEmoji renders GitLab's AwardEmoji envelope over it - the same rows GitHub serves as reactions and Azure DevOps as comment reactions", mode_reviewed: "2026-09-07", tag: "Award emoji", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{merge_request_iid}/award_emoji/{award_id}", area: "award emoji", tier: 3, status: "green", mode: "derive", mode_reason: "ContentReaction is canon as of hello-15 (features.contentReactions): one row per person per gesture per target, with an id, a discriminated target and an instant. reactionsFor() answers it and renderer-gitlab's glAwardEmoji renders GitLab's AwardEmoji envelope over it - the same rows GitHub serves as reactions and Azure DevOps as comment reactions", mode_reviewed: "2026-09-07", tag: "Award emoji", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{merge_request_iid}/blockees", area: "merge-requests", tier: 1, status: "green", mode: "empty", mode_reason: "canon models no dependency between merge requests, so no merge request blocks or is blocked by another", mode_reviewed: "2026-09-01", tag: "Merge requests" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{merge_request_iid}/blocks", area: "merge-requests", tier: 1, status: "green", mode: "empty", mode_reason: "the other direction of the merge-request dependency pair, held to the same fact: canon models no dependency between merge requests", mode_reviewed: "2026-09-01", tag: "Merge requests" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{merge_request_iid}/blocks/{block_id}", area: "merge-requests", tier: 1, status: "planned", mode: "refuse", mode_reason: "the collection this id would index is empty in this universe, so the only honest answer is the vendor's own 404", mode_reviewed: "2026-09-01", tag: "Merge requests" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{merge_request_iid}/changes", area: "merge-requests", tier: 1, status: "deviation", mode: "derive", mode_reviewed: "2026-09-01", tag: "Merge requests" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{merge_request_iid}/closes_issues", area: "merge-requests", tier: 1, status: "deviation", mode: "derive", mode_reviewed: "2026-09-01", tag: "Merge requests" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{merge_request_iid}/commits", area: "merge-requests", tier: 1, status: "green", mode: "derive", tag: "Merge requests" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{merge_request_iid}/context_commits", area: "merge-requests", tier: 1, status: "green", mode: "empty", mode_reason: "a context commit is one a person manually ATTACHES to a merge request to widen the diff a reviewer sees. It is an action, canon models no such action, and so no merge request carries one. Unpaginated: the vendored document declares no page/per_page on this operation. RULED by the founder 2026-09-09", mode_reviewed: "2026-09-09", tag: "Merge requests" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{merge_request_iid}/diffs", area: "merge-requests", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Merge requests" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{merge_request_iid}/draft_notes", area: "merge-requests", tier: 1, status: "green", mode: "empty", mode_reason: "a draft note is an unsubmitted review comment, by definition never visible to anyone but its author; every review in this universe is already submitted, so the draft list is truthfully empty", mode_reviewed: "2026-09-01", tag: "Draft notes" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{merge_request_iid}/draft_notes/{draft_note_id}", area: "merge-requests", tier: 1, status: "planned", mode: "refuse", mode_reason: "the collection this id would index is empty in this universe, so the only honest answer is the vendor's own 404", mode_reviewed: "2026-09-01", tag: "Draft notes" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{merge_request_iid}/merge_ref", area: "merge-requests", tier: 1, status: "planned", mode: "refuse", mode_reason: "the head of refs/merge-requests/{iid}/merge — a commit produced by MERGING source into target. GitLab writes that ref from a mergeability check and refuses with the documented 400 when the check does not succeed, which is every settled merge request; for an open one canon records no merge result and the sha would have to be invented. RULED by the founder 2026-09-09", mode_reviewed: "2026-09-09", tag: "Merge requests" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{merge_request_iid}/notes/{note_id}/award_emoji", area: "award emoji", tier: 3, status: "green", mode: "derive", mode_reason: "ContentReaction is canon as of hello-15 (features.contentReactions): one row per person per gesture per target, with an id, a discriminated target and an instant. reactionsFor() answers it and renderer-gitlab's glAwardEmoji renders GitLab's AwardEmoji envelope over it - the same rows GitHub serves as reactions and Azure DevOps as comment reactions", mode_reviewed: "2026-09-07", tag: "Award emoji", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{merge_request_iid}/notes/{note_id}/award_emoji/{award_id}", area: "award emoji", tier: 3, status: "green", mode: "derive", mode_reason: "ContentReaction is canon as of hello-15 (features.contentReactions): one row per person per gesture per target, with an id, a discriminated target and an instant. reactionsFor() answers it and renderer-gitlab's glAwardEmoji renders GitLab's AwardEmoji envelope over it - the same rows GitHub serves as reactions and Azure DevOps as comment reactions", mode_reviewed: "2026-09-07", tag: "Award emoji", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{merge_request_iid}/participants", area: "merge-requests", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Merge requests" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{merge_request_iid}/pipelines", area: "merge-requests", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Merge requests" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{merge_request_iid}/raw_diffs", area: "merge-requests", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Merge requests" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{merge_request_iid}/related_issues", area: "merge-requests", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Merge requests" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{merge_request_iid}/reviewers", area: "merge-requests", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Merge requests" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{merge_request_iid}/status_checks", area: "external status checks", tier: 3, status: "green", mode: "empty", mode_reason: "olympus-labs protects only branches — canon's protected_ref carries two branch patterns at namespace scope and no environment, tag, merge train, push rule or external status check exists; GitLab answers `[]` at 200 for each of these lists and its own 404 for a named one. THE LIST HALF, and the merge request RESOLVES — so the empty page is a statement about that merge request rather than about an iid nobody has. Served UNPAGINATED because the vendored operation declares only its two path parameters; printing pagination headers on an operation GitLab does not paginate would break invariant #2 in the name of consistency. UNGATED: no generation of this universe has ever protected an environment or a tag, queued a merge train, registered an external status check or set a push rule. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "External status checks", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{merge_request_iid}/time_stats", area: "merge-requests", tier: 1, status: "deviation", mode: "empty", mode_reason: "no persona in olympus-labs logs time against an issue or a merge request — canon records no TimeEntry; GitLab's own answer for an untracked issue is a 200 carrying `time_estimate: 0`, `total_time_spent: 0` and both human_ fields null. NOT A COLLECTION: the operation returns `APIEntitiesIssuableTimeStats`, an object, so the honest empty is the zeroed object rather than `[]`. It is the SAME object `glIssue` and `glMergeRequest` already embed as `time_stats` (`emptyTimeStats` in packages/renderer-gitlab/src/render2.ts), read from one function so the standalone endpoint and the embedded block can never disagree (invariant #5). canon's `Issue.estimate` is a story-point estimate on a fibonacci scale rather than a duration, and `time_estimate` is documented in seconds, so mapping one onto the other would be an invention. The two human_ fields are a `deviation` against the vendored component, which types them `string` with no `nullable` while real GitLab renders nil for a zero — the same two entries NULLABLE_SPEC_BUGS already carries for the embedded block. UNGATED: no generation of this universe records a time entry. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Merge requests" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{merge_request_iid}/versions", area: "merge-requests", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Merge requests" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{merge_request_iid}/versions/{version_id}", area: "merge-requests", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Merge requests" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{noteable_id}/discussions", area: "discussions", tier: 1, status: "deviation", mode: "derive", mode_reviewed: "2026-09-01", tag: "Discussions" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{noteable_id}/discussions/{discussion_id}", area: "discussions", tier: 1, status: "deviation", mode: "derive", mode_reviewed: "2026-09-01", tag: "Discussions" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{noteable_id}/discussions/{discussion_id}/notes", area: "discussions", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Discussions" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{noteable_id}/discussions/{discussion_id}/notes/{note_id}", area: "discussions", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Discussions" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{noteable_id}/notes", area: "notes", tier: 1, status: "green", mode: "derive", tag: "Notes" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_requests/{noteable_id}/notes/{note_id}", area: "notes", tier: 1, status: "green", mode: "derive", tag: "Notes" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_trains", area: "merge trains", tier: 3, status: "green", mode: "empty", mode_reason: "olympus-labs protects only branches — canon's protected_ref carries two branch patterns at namespace scope and no environment, tag, merge train, push rule or external status check exists; GitLab answers `[]` at 200 for each of these lists and its own 404 for a named one. THE LIST HALF, served as GitLab's empty page with the pagination headers the operation declares. UNGATED: no generation of this universe has ever protected an environment or a tag, queued a merge train, registered an external status check or set a push rule, so every registered pin answers this same `[]`. Falsifiable: the `expectsEmpty` conformance entry reds the row the day canon grows one. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Merge trains", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_trains/{target_branch}", area: "merge trains", tier: 3, status: "deferred", mode: "refuse", mode_reason: "olympus-labs protects only branches — canon's protected_ref carries two branch patterns at namespace scope and no environment, tag, merge train, push rule or external status check exists; GitLab answers `[]` at 200 for each of these lists and its own 404 for a named one. THE NAMED HALF: no name resolves over a collection that is empty, so GitLab's own 404 is the whole answer — `[]` here would assert that the thing exists and holds nothing. UNGATED: no generation of this universe has ever protected an environment or a tag, queued a merge train, registered an external status check or set a push rule, so the 404 is true on every artifact. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Merge trains", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/merge_trains/merge_requests/{merge_request_iid}", area: "merge trains", tier: 3, status: "deferred", mode: "refuse", mode_reason: "olympus-labs protects only branches — canon's protected_ref carries two branch patterns at namespace scope and no environment, tag, merge train, push rule or external status check exists; GitLab answers `[]` at 200 for each of these lists and its own 404 for a named one. THE NAMED HALF: no name resolves over a collection that is empty, so GitLab's own 404 is the whole answer — `[]` here would assert that the thing exists and holds nothing. UNGATED: no generation of this universe has ever protected an environment or a tag, queued a merge train, registered an external status check or set a push rule, so the 404 is true on every artifact. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Merge trains", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/milestones", area: "milestones", tier: 1, status: "deviation", mode: "derive", tag: "Milestones" }
      - { method: "GET", path: "/api/v4/projects/{id}/milestones/{milestone_id}", area: "milestones", tier: 1, status: "deviation", mode: "derive", mode_reviewed: "2026-09-01", tag: "Milestones" }
      - { method: "GET", path: "/api/v4/projects/{id}/milestones/{milestone_id}/burndown_events", area: "milestones", tier: 1, status: "planned", mode: "generate", mode_reason: "canon keeps current label/milestone state, not its history; needs a ResourceEvent log", mode_reviewed: "2026-09-01", tag: "Milestones" }
      - { method: "GET", path: "/api/v4/projects/{id}/milestones/{milestone_id}/issues", area: "milestones", tier: 1, status: "deviation", mode: "derive", mode_reviewed: "2026-09-01", tag: "Milestones" }
      - { method: "GET", path: "/api/v4/projects/{id}/milestones/{milestone_id}/merge_requests", area: "milestones", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Milestones" }
      - { method: "GET", path: "/api/v4/projects/{id}/mirror/pull", area: "project mirrors", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the collection this id would index is empty in this universe, so the only honest answer is the vendor's own 404", mode_reviewed: "2026-09-01", tag: "Project mirrors", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/ml/mlflow/api/2.0/mlflow-artifacts/artifacts", area: "mlops", tier: 3, status: "deferred", mode: "refuse", mode_reason: "mirroring GitLab MLflow means simulating a second ML platform with no bearing on the dev-tool story; GitLab 404s these for a project with no experiments", mode_reviewed: "2026-09-01", tag: "MLOps", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/ml/mlflow/api/2.0/mlflow/experiments/get", area: "mlops", tier: 3, status: "deferred", mode: "refuse", mode_reason: "mirroring GitLab MLflow means simulating a second ML platform with no bearing on the dev-tool story; GitLab 404s these for a project with no experiments", mode_reviewed: "2026-09-01", tag: "MLOps", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/ml/mlflow/api/2.0/mlflow/experiments/get-by-name", area: "mlops", tier: 3, status: "deferred", mode: "refuse", mode_reason: "mirroring GitLab MLflow means simulating a second ML platform with no bearing on the dev-tool story; GitLab 404s these for a project with no experiments", mode_reviewed: "2026-09-01", tag: "MLOps", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/ml/mlflow/api/2.0/mlflow/experiments/list", area: "mlops", tier: 3, status: "deferred", mode: "refuse", mode_reason: "mirroring GitLab MLflow means simulating a second ML platform with no bearing on the dev-tool story; GitLab 404s these for a project with no experiments", mode_reviewed: "2026-09-01", tag: "MLOps", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/ml/mlflow/api/2.0/mlflow/metrics/get-history", area: "mlops", tier: 3, status: "deferred", mode: "refuse", mode_reason: "mirroring GitLab MLflow means simulating a second ML platform with no bearing on the dev-tool story; GitLab 404s these for a project with no experiments", mode_reviewed: "2026-09-01", tag: "MLOps", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/ml/mlflow/api/2.0/mlflow/model-versions/get", area: "mlops", tier: 3, status: "deferred", mode: "refuse", mode_reason: "mirroring GitLab MLflow means simulating a second ML platform with no bearing on the dev-tool story; GitLab 404s these for a project with no experiments", mode_reviewed: "2026-09-01", tag: "MLOps", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/ml/mlflow/api/2.0/mlflow/model-versions/get-download-uri", area: "mlops", tier: 3, status: "deferred", mode: "refuse", mode_reason: "mirroring GitLab MLflow means simulating a second ML platform with no bearing on the dev-tool story; GitLab 404s these for a project with no experiments", mode_reviewed: "2026-09-01", tag: "MLOps", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/ml/mlflow/api/2.0/mlflow/registered-models/alias", area: "mlops", tier: 3, status: "deferred", mode: "refuse", mode_reason: "mirroring GitLab MLflow means simulating a second ML platform with no bearing on the dev-tool story; GitLab 404s these for a project with no experiments", mode_reviewed: "2026-09-01", tag: "MLOps", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/ml/mlflow/api/2.0/mlflow/registered-models/get", area: "mlops", tier: 3, status: "deferred", mode: "refuse", mode_reason: "mirroring GitLab MLflow means simulating a second ML platform with no bearing on the dev-tool story; GitLab 404s these for a project with no experiments", mode_reviewed: "2026-09-01", tag: "MLOps", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/ml/mlflow/api/2.0/mlflow/registered-models/search", area: "mlops", tier: 3, status: "deferred", mode: "refuse", mode_reason: "mirroring GitLab MLflow means simulating a second ML platform with no bearing on the dev-tool story; GitLab 404s these for a project with no experiments", mode_reviewed: "2026-09-01", tag: "MLOps", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/ml/mlflow/api/2.0/mlflow/runs/get", area: "mlops", tier: 3, status: "deferred", mode: "refuse", mode_reason: "mirroring GitLab MLflow means simulating a second ML platform with no bearing on the dev-tool story; GitLab 404s these for a project with no experiments", mode_reviewed: "2026-09-01", tag: "MLOps", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/notification_settings", area: "notification settings", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no NotificationSetting for a persona", mode_reviewed: "2026-09-01", tag: "Notification settings", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/{package_id}", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/{package_id}/package_files", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/{package_id}/package_files/{package_file_id}/download", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/{package_id}/pipelines", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/cargo/{package_name}/{package_version}/download", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Cargo" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/cargo/{prefix_1}/{prefix_2}/{package_name}", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Cargo" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/cargo/1/{package_name}", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Cargo" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/cargo/2/{package_name}", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Cargo" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/cargo/3/{first_char}/{package_name}", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Cargo" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/cargo/config.json", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Cargo" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/conan/v1/conans/{package_name}/{package_version}/{package_username}/{package_channel}", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/conan/v1/conans/{package_name}/{package_version}/{package_username}/{package_channel}/digest", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/conan/v1/conans/{package_name}/{package_version}/{package_username}/{package_channel}/download_urls", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/conan/v1/conans/{package_name}/{package_version}/{package_username}/{package_channel}/packages/{conan_package_reference}", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/conan/v1/conans/{package_name}/{package_version}/{package_username}/{package_channel}/packages/{conan_package_reference}/digest", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/conan/v1/conans/{package_name}/{package_version}/{package_username}/{package_channel}/packages/{conan_package_reference}/download_urls", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/conan/v1/conans/{package_name}/{package_version}/{package_username}/{package_channel}/search", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/conan/v1/conans/search", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/conan/v1/files/{package_name}/{package_version}/{package_username}/{package_channel}/{recipe_revision}/export/{file_name}", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/conan/v1/files/{package_name}/{package_version}/{package_username}/{package_channel}/{recipe_revision}/package/{conan_package_reference}/{package_revision}/{file_name}", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/conan/v1/ping", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/conan/v1/users/authenticate", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/conan/v1/users/check_credentials", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/conan/v2/conans/{package_name}/{package_version}/{package_username}/{package_channel}/latest", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/conan/v2/conans/{package_name}/{package_version}/{package_username}/{package_channel}/revisions", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/conan/v2/conans/{package_name}/{package_version}/{package_username}/{package_channel}/revisions/{recipe_revision}/files", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/conan/v2/conans/{package_name}/{package_version}/{package_username}/{package_channel}/revisions/{recipe_revision}/files/{file_name}", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/conan/v2/conans/{package_name}/{package_version}/{package_username}/{package_channel}/revisions/{recipe_revision}/packages/{conan_package_reference}/latest", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/conan/v2/conans/{package_name}/{package_version}/{package_username}/{package_channel}/revisions/{recipe_revision}/packages/{conan_package_reference}/revisions", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/conan/v2/conans/{package_name}/{package_version}/{package_username}/{package_channel}/revisions/{recipe_revision}/packages/{conan_package_reference}/revisions/{package_revision}/files", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/conan/v2/conans/{package_name}/{package_version}/{package_username}/{package_channel}/revisions/{recipe_revision}/packages/{conan_package_reference}/revisions/{package_revision}/files/{file_name}", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/conan/v2/conans/{package_name}/{package_version}/{package_username}/{package_channel}/revisions/{recipe_revision}/search", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/conan/v2/conans/{package_name}/{package_version}/{package_username}/{package_channel}/search", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/conan/v2/conans/search", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/conan/v2/users/authenticate", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/conan/v2/users/check_credentials", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Conan" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/debian/pool/{distribution}/{letter}/{package_name}/{package_version}/{file_name}", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Debian" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/helm/{channel}/charts/{file_name}.tgz", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Helm" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/helm/{channel}/index.yaml", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: Helm" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/nuget/index", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: NuGet" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/nuget/query", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: NuGet" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/nuget/v2", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: NuGet" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/nuget/v2/$metadata", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: NuGet" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/protection/rules", area: "projects", tier: 1, status: "green", mode: "empty", mode_reason: "these govern who may PUBLISH into a registry; a read-only mirror accepts no publishes, so nothing has ever configured a rule here — and real GitLab answers a project with none configured 200 []", mode_reviewed: "2026-09-03", tag: "Projects" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/pypi/simple", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: PyPi" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/rubygems/{file_name}", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: RubyGem" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/rubygems/api/v1/dependencies", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: RubyGem" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/rubygems/gems/{file_name}", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: RubyGem" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/rubygems/quick/Marshal.4.8/{file_name}", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: RubyGem" }
      - { method: "GET", path: "/api/v4/projects/{id}/packages/terraform/modules/{module_name}/{module_system}", area: "terraform", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Terraform", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/pages", area: "gitlab pages", tier: 3, status: "deferred", mode: "refuse", mode_reason: "olympus-labs publishes no GitLab Pages site — no project in this universe has a pages deployment or a custom domain; GitLab's own 404 for a project with Pages unused is the whole answer. ALL FOUR ROWS REFUSE, the domain list included: a Pages domain collection is addressable only on a project that HAS Pages, and no project here does — a 200 `[]` there would advertise a Pages site with no custom domain rather than the absence of Pages. The vendored document declares `404 Not Found` on all four operations. UNGATED: canon has no PagesSite in any generation. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "GitLab Pages", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/pages_access", area: "projects", tier: 1, status: "planned", mode: "refuse", mode_reason: "olympus-labs publishes no GitLab Pages site — no project in this universe has a pages deployment or a custom domain; GitLab's own 404 for a project with Pages unused is the whole answer. ALL FOUR ROWS REFUSE, the domain list included: a Pages domain collection is addressable only on a project that HAS Pages, and no project here does — a 200 `[]` there would advertise a Pages site with no custom domain rather than the absence of Pages. The vendored document declares `404 Not Found` on all four operations. UNGATED: canon has no PagesSite in any generation. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Projects" }
      - { method: "GET", path: "/api/v4/projects/{id}/pages/domains", area: "gitlab pages", tier: 3, status: "deferred", mode: "refuse", mode_reason: "olympus-labs publishes no GitLab Pages site — no project in this universe has a pages deployment or a custom domain; GitLab's own 404 for a project with Pages unused is the whole answer. ALL FOUR ROWS REFUSE, the domain list included: a Pages domain collection is addressable only on a project that HAS Pages, and no project here does — a 200 `[]` there would advertise a Pages site with no custom domain rather than the absence of Pages. The vendored document declares `404 Not Found` on all four operations. UNGATED: canon has no PagesSite in any generation. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "GitLab Pages", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/pages/domains/{domain}", area: "gitlab pages", tier: 3, status: "deferred", mode: "refuse", mode_reason: "olympus-labs publishes no GitLab Pages site — no project in this universe has a pages deployment or a custom domain; GitLab's own 404 for a project with Pages unused is the whole answer. ALL FOUR ROWS REFUSE, the domain list included: a Pages domain collection is addressable only on a project that HAS Pages, and no project here does — a 200 `[]` there would advertise a Pages site with no custom domain rather than the absence of Pages. The vendored document declares `404 Not Found` on all four operations. UNGATED: canon has no PagesSite in any generation. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "GitLab Pages", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/pipeline_schedules", area: "pipelines", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W8) (hello-15 `ciConfig`): reader.listWorkflowSchedules(repo) over canon.WorkflowSchedule. `description` and `ref` are the schedule's own description and branch, `owner` is the actor it runs as, `created_at` and `updated_at` its two epochs, `cron_timezone` UTC because canon's hours ARE UTC, and `cron` is the (per_hour, hours_of_day, days_of_week) triple re-encoded LOSSLESSLY — every value in the triple appears in the expression and nothing else does, which conformance checks field by field rather than against a literal. `active` is true because every schedule here really starts runs, and an inactive schedule that had started 398 pipelines would contradict its own pipeline list. `next_run_at` is walked forward from THE ARTIFACT'S ANCHOR, never Date.now(): a frozen pin must print the same instant in a year's time. `inputs` and `variables` are omitted — canon carries no schedule variable of any kind. GENERATION-GATED: an older artifact answers the CI-configuration gap rather than `[]`, which would say nothing here runs unattended. `scope=inactive` is a real filter that truthfully matches nothing, the posture `pipelines?status=` takes for a value this generator never produces", mode_reviewed: "2026-09-12", tag: "Pipeline schedules" }
      - { method: "GET", path: "/api/v4/projects/{id}/pipeline_schedules/{pipeline_schedule_id}", area: "pipelines", tier: 2, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W8) (hello-15 `ciConfig`): reader.listWorkflowSchedules(repo) over canon.WorkflowSchedule. `description` and `ref` are the schedule's own description and branch, `owner` is the actor it runs as, `created_at` and `updated_at` its two epochs, `cron_timezone` UTC because canon's hours ARE UTC, and `cron` is the (per_hour, hours_of_day, days_of_week) triple re-encoded LOSSLESSLY — every value in the triple appears in the expression and nothing else does, which conformance checks field by field rather than against a literal. `active` is true because every schedule here really starts runs, and an inactive schedule that had started 398 pipelines would contradict its own pipeline list. `next_run_at` is walked forward from THE ARTIFACT'S ANCHOR, never Date.now(): a frozen pin must print the same instant in a year's time. `inputs` is omitted — canon carries no schedule input. GENERATION-GATED: an older artifact answers the CI-configuration gap rather than `[]`, which would say nothing here runs unattended. The detail shape adds `last_pipeline`, and it is the newest run THIS SCHEDULE started (reader.runsForSchedule) rather than the project's newest pipeline — conformance asserts every other field is byte-identical to the list row's. VARIABLES SERVED 2026-09-13 (hello-19 `ciBindings`), AND THIS ROW IS A `deviation` BECAUSE OF THEM: the detail shape also publishes the schedule's CI/CD variables, off the SAME glScheduleVariables the by-key row /pipeline_schedules/{id}/variables/{key} reads, so the two surfaces cannot disagree about one fact — conformance compares the block to that URL's bytes element for element. A masked binding renders `masked: true, hidden: true` and ships NO `value` key, here as everywhere: no ci_binding row carries a value when masked = 1 (compiler/src/hello19.test.ts asserts it as SQL over every compiled artifact). THE DEVIATION IS THE VENDORED DOCUMENT'S: APIEntitiesCiPipelineScheduleDetails types `variables` as a SINGLE APIEntitiesCiVariable object while real GitLab sends an ARRAY — `Ci::PipelineSchedule has_many :variables`, `Entities::Ci::PipelineScheduleDetails` exposes them `using: Entities::Ci::Variable` over that association, and GitLab's own published example for this operation shows `\"variables\": [{...}]`. Invariant #2 mirrors the provider rather than its documentation, so the array is served and the one validator error is declared a spec bug (SCHEDULE_VARIABLES_SPEC_BUGS); the vendored file is upstream-verbatim and sha256-pinned, so it is NOT edited — the correction and the evidence live in conformance and in coverage/provider-pins.yaml. Same class as `approved_by` on the code-review component. The `variables` KEY IS ABSENT rather than `[]` on a pre-hello-19 artifact: [] would say this organization hands its nightly release nothing while the same artifact publishes a CI document, a schedule that starts real runs and deployments to two environments, and a whole-response coverage 404 would break invariant #2 on all 127 frozen pins, which fetch this row and get GitLab's 200. gitlab/hello19.test.ts asserts the row gains exactly that one key and nothing else", mode_reviewed: "2026-09-13", tag: "Pipeline schedules" }
      - { method: "GET", path: "/api/v4/projects/{id}/pipeline_schedules/{pipeline_schedule_id}/pipelines", area: "pipelines", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W8) (hello-15 `ciConfig`): the runs one schedule started — reader.runsForSchedule(id), reading `workflow_run.schedule` directly. hello-15's schedule starts REAL runs carrying event `schedule`, and they drive the RELEASE workflow while `/projects/{id}/pipelines` lists the `ci` one — so they are deliberately NOT in that feed, and the 2026-09-09 reason that said they were is corrected here. WHAT WOULD HAVE BEEN AN INVARIANT-#5 BREAK IS NAMING A PIPELINE THIS HOST THEN REFUSES TO FETCH, and this wave closed it: `findPipeline` resolves ANY run of the project rather than only a `ci` one, so every id in this list answers at `/pipelines/{pipeline_id}` and its jobs answer too, which conformance drives row by row. The LIST is deliberately left alone — widening it to all 398 runs would move bytes every frozen pin already serves. Generation-gated with the rest of the family", mode_reviewed: "2026-09-12", tag: "Pipeline schedules" }
      - { method: "GET", path: "/api/v4/projects/{id}/pipeline_schedules/{pipeline_schedule_id}/variables/{key}", area: "pipelines", tier: 2, status: "green", mode: "derive", mode_reason: "the nightly release's publishing credential, off reader.scheduleCiBindings(schedule) — a job that runs unattended cannot be handed its credential by a person, which is why the binding is stored on the schedule rather than pasted into a run. THE SAME BYTES ITS OWN RUNS PUBLISH: conformance compares this response to /pipelines/{pipeline_id}/variables on a run this schedule started, so one fact cannot be answered two ways. GitLab's own `404 Not found` for an unknown schedule or key, `%ZZ` included. SERVED 2026-09-12 (hello-19 `ciBindings`): the 2026-09-09 re-scope asked for a variable table and named the constraint that would make one honest — a masked value is a secret canon stores none of. hello-19's `ci_binding` is that table, built on exactly that constraint: one row, one `masked` boolean, and NO VALUE IN ANY COLUMN on a masked row (`compiler/src/hello19.test.ts` asserts `COUNT(*) WHERE masked = 1 AND value IS NOT NULL` is 0 on every compiled artifact). A MASKED BINDING RENDERS `hidden: true` AND SHIPS NO `value` KEY, which is GitLab's own vocabulary rather than a convenience: `masked` means blanked out of JOB LOGS and `hidden` (created as `masked_and_hidden`) means THE API NEVER RETURNS THE VALUE, so `masked: true, hidden: false` with the key dropped would be a shape real GitLab never sends. An unmasked binding's `value` is the artifact row `ci_binding.value_source` names — the collector's endpoint, the default branch, the orb document's tree path — resolved at compile time, so the setting and the thing it configures cannot drift apart. `variable_type` is `env_var` on every row, which agrees with /api/v4/projects/{id}/secure_files being ruled empty: a `file` variable IS a secure file. `raw` and `description` are OMITTED rather than defaulted — neither is required by APIEntitiesCiVariable and neither is a fact canon holds (the depth-hooks.ts rule, one wave earlier). Conformance drives each row against the vendored schema AND against the reader accessor the renderer must have used, walks the pages with the headers asserted, and fails if a masked row ever carries a value. Gated on hasCiBindings(); an older artifact answers the named hello-19 CI-variable gap, because [] there would say this organization configures its pipelines with nothing while the same artifact publishes a CI document, a nightly schedule and deployments to two environments", mode_reviewed: "2026-09-12", tag: "Pipeline schedules" }
      - { method: "GET", path: "/api/v4/projects/{id}/pipelines", area: "pipelines", tier: 2, status: "green", mode: "derive", tag: "Pipelines" }
      - { method: "GET", path: "/api/v4/projects/{id}/pipelines/{pipeline_id}", area: "pipelines", tier: 2, status: "green", mode: "derive", tag: "Pipelines" }
      - { method: "GET", path: "/api/v4/projects/{id}/pipelines/{pipeline_id}/bridges", area: "pipelines", tier: 2, status: "green", mode: "empty", mode_reason: "a bridge is a job that triggers a downstream pipeline; this universe's CI is a single project's pipeline with no downstream trigger, so the bridge list is truthfully empty", mode_reviewed: "2026-09-01", tag: "Pipelines" }
      - { method: "GET", path: "/api/v4/projects/{id}/pipelines/{pipeline_id}/jobs", area: "pipelines", tier: 2, status: "green", mode: "derive", tag: "Pipelines" }
      - { method: "GET", path: "/api/v4/projects/{id}/pipelines/{pipeline_id}/test_report", area: "pipelines", tier: 2, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W8) (hello-15 `ciConfig`): reader.testResultsForJob(job) over canon.TestCase/TestResult, folded PER JOB — GitLab keys a test report's suites by the BUILD that reported them, which is what makes one suite per job the mirror rather than a choice. canon spells a failure \"failure\" and GitLab spells it \"failed\"; the other three statuses agree. `system_output` is the reporter's message and is absent on a pass, because canon stores NULL there rather than an empty string. `file`, `stack_trace`, `recent_failures` and `attachment_url` are omitted — canon records none of them. The durations are FLOAT seconds as real GitLab sends them while both vendored components type them `integer`, so the row is a `deviation` rather than rounding canon's millisecond durations away. Generation-gated: an older artifact answers the CI-configuration gap rather than a report of no tests. Conformance recomputes every counter from the artifact and asserts each served case is one canon DECLARES, with canon's own classname — a test name invented here would be a test nobody wrote", mode_reviewed: "2026-09-12", tag: "Pipelines" }
      - { method: "GET", path: "/api/v4/projects/{id}/pipelines/{pipeline_id}/test_report_summary", area: "pipelines", tier: 2, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W8) (hello-15 `ciConfig`): reader.testResultsForJob(job) over canon.TestCase/TestResult, folded PER JOB — GitLab keys a test report's suites by the BUILD that reported them, which is what makes one suite per job the mirror rather than a choice. canon spells a failure \"failure\" and GitLab spells it \"failed\"; the other three statuses agree. `system_output` is the reporter's message and is absent on a pass, because canon stores NULL there rather than an empty string. `file`, `stack_trace`, `recent_failures` and `attachment_url` are omitted — canon records none of them. The durations are FLOAT seconds as real GitLab sends them while both vendored components type them `integer`, so the row is a `deviation` rather than rounding canon's millisecond durations away. Generation-gated: an older artifact answers the CI-configuration gap rather than a report of no tests. The SAME fold, totals only: the summary carries `build_ids` and no `test_cases`, which is the whole difference between the two operations and the reason both exist. Conformance asserts the two endpoints agree counter for counter — two different totals for one pipeline would be this host describing two universes of tests. `test_suites` is a `deviation`, the vendored component typing the collection as one object", mode_reviewed: "2026-09-12", tag: "Pipelines" }
      - { method: "GET", path: "/api/v4/projects/{id}/pipelines/{pipeline_id}/trigger_jobs", area: "pipelines", tier: 2, status: "green", mode: "empty", mode_reason: "GitLab's other name for the same thing the bridges row carries, held to the same fact: this CI triggers no downstream pipeline", mode_reviewed: "2026-09-01", tag: "Pipelines" }
      - { method: "GET", path: "/api/v4/projects/{id}/pipelines/{pipeline_id}/variables", area: "pipelines", tier: 2, status: "green", mode: "derive", mode_reason: "the variables ONE RUN WAS STARTED WITH — a genuinely two-branch answer, and `workflow_run.schedule` is the column that tells the branches apart without a join. A run a schedule started carries that schedule's bindings (reader.scheduleCiBindings); a run somebody pushed was started with none and answers [] at 200, which is the true answer rather than a gap. 86 of this universe's 350 runs at 90 days carry a schedule, so conformance drives both branches and fails if either becomes unreachable. The pipeline id resolves FIRST, on every generation: an id this project does not have is GitLab's own `404 Not found`. SERVED 2026-09-12 (hello-19 `ciBindings`): the 2026-09-09 re-scope asked for a variable table and named the constraint that would make one honest — a masked value is a secret canon stores none of. hello-19's `ci_binding` is that table, built on exactly that constraint: one row, one `masked` boolean, and NO VALUE IN ANY COLUMN on a masked row (`compiler/src/hello19.test.ts` asserts `COUNT(*) WHERE masked = 1 AND value IS NOT NULL` is 0 on every compiled artifact). A MASKED BINDING RENDERS `hidden: true` AND SHIPS NO `value` KEY, which is GitLab's own vocabulary rather than a convenience: `masked` means blanked out of JOB LOGS and `hidden` (created as `masked_and_hidden`) means THE API NEVER RETURNS THE VALUE, so `masked: true, hidden: false` with the key dropped would be a shape real GitLab never sends. An unmasked binding's `value` is the artifact row `ci_binding.value_source` names — the collector's endpoint, the default branch, the orb document's tree path — resolved at compile time, so the setting and the thing it configures cannot drift apart. `variable_type` is `env_var` on every row, which agrees with /api/v4/projects/{id}/secure_files being ruled empty: a `file` variable IS a secure file. `raw` and `description` are OMITTED rather than defaulted — neither is required by APIEntitiesCiVariable and neither is a fact canon holds (the depth-hooks.ts rule, one wave earlier). Conformance drives each row against the vendored schema AND against the reader accessor the renderer must have used, walks the pages with the headers asserted, and fails if a masked row ever carries a value. Gated on hasCiBindings(); an older artifact answers the named hello-19 CI-variable gap, because [] there would say this organization configures its pipelines with nothing while the same artifact publishes a CI document, a nightly schedule and deployments to two environments", mode_reviewed: "2026-09-12", tag: "Pipelines" }
      - { method: "GET", path: "/api/v4/projects/{id}/pipelines/latest", area: "pipelines", tier: 2, status: "green", mode: "derive", tag: "Pipelines" }
      - { method: "GET", path: "/api/v4/projects/{id}/protected_branches", area: "protected-branches", tier: 2, status: "green", mode: "derive", tag: "Protected branches" }
      - { method: "GET", path: "/api/v4/projects/{id}/protected_branches/{name}", area: "protected-branches", tier: 2, status: "green", mode: "derive", tag: "Protected branches" }
      - { method: "GET", path: "/api/v4/projects/{id}/protected_environments", area: "deployments", tier: 2, status: "green", mode: "empty", mode_reason: "olympus-labs protects only branches — canon's protected_ref carries two branch patterns at namespace scope and no environment, tag, merge train, push rule or external status check exists; GitLab answers `[]` at 200 for each of these lists and its own 404 for a named one. THE LIST HALF, served as GitLab's empty page with the pagination headers the operation declares. UNGATED: no generation of this universe has ever protected an environment or a tag, queued a merge train, registered an external status check or set a push rule, so every registered pin answers this same `[]`. Falsifiable: the `expectsEmpty` conformance entry reds the row the day canon grows one. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Protected environments" }
      - { method: "GET", path: "/api/v4/projects/{id}/protected_environments/{name}", area: "deployments", tier: 2, status: "deferred", mode: "refuse", mode_reason: "olympus-labs protects only branches — canon's protected_ref carries two branch patterns at namespace scope and no environment, tag, merge train, push rule or external status check exists; GitLab answers `[]` at 200 for each of these lists and its own 404 for a named one. THE NAMED HALF: no name resolves over a collection that is empty, so GitLab's own 404 is the whole answer — `[]` here would assert that the thing exists and holds nothing. UNGATED: no generation of this universe has ever protected an environment or a tag, queued a merge train, registered an external status check or set a push rule, so the 404 is true on every artifact. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Protected environments" }
      - { method: "GET", path: "/api/v4/projects/{id}/protected_tags", area: "protected-branches", tier: 2, status: "green", mode: "empty", mode_reason: "olympus-labs protects only branches — canon's protected_ref carries two branch patterns at namespace scope and no environment, tag, merge train, push rule or external status check exists; GitLab answers `[]` at 200 for each of these lists and its own 404 for a named one. THE LIST HALF, served as GitLab's empty page with the pagination headers the operation declares. UNGATED: no generation of this universe has ever protected an environment or a tag, queued a merge train, registered an external status check or set a push rule, so every registered pin answers this same `[]`. Falsifiable: the `expectsEmpty` conformance entry reds the row the day canon grows one. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Protected tags" }
      - { method: "GET", path: "/api/v4/projects/{id}/protected_tags/{name}", area: "protected-branches", tier: 2, status: "deferred", mode: "refuse", mode_reason: "olympus-labs protects only branches — canon's protected_ref carries two branch patterns at namespace scope and no environment, tag, merge train, push rule or external status check exists; GitLab answers `[]` at 200 for each of these lists and its own 404 for a named one. THE NAMED HALF: no name resolves over a collection that is empty, so GitLab's own 404 is the whole answer — `[]` here would assert that the thing exists and holds nothing. UNGATED: no generation of this universe has ever protected an environment or a tag, queued a merge train, registered an external status check or set a push rule, so the 404 is true on every artifact. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Protected tags" }
      - { method: "GET", path: "/api/v4/projects/{id}/push_rule", area: "push rules", tier: 3, status: "deferred", mode: "refuse", mode_reason: "olympus-labs protects only branches — canon's protected_ref carries two branch patterns at namespace scope and no environment, tag, merge train, push rule or external status check exists; GitLab answers `[]` at 200 for each of these lists and its own 404 for a named one. NOT A NAMED HALF AND NOT A COLLECTION: `push_rule` is a SINGULAR sub-resource that takes no name, so `[]` is not a shape it can take at all — there is simply no rule object to render, and the vendored operation declares exactly two responses, a 200 with the rule and a 404 without one. UNGATED: no generation of this universe has ever protected an environment or a tag, queued a merge train, registered an external status check or set a push rule. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Push rules", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/registry/protection/repository/rules", area: "projects", tier: 1, status: "green", mode: "empty", mode_reason: "these govern who may PUBLISH into a registry; a read-only mirror accepts no publishes, so nothing has ever configured a rule here — and real GitLab answers a project with none configured 200 []", mode_reviewed: "2026-09-03", tag: "Projects" }
      - { method: "GET", path: "/api/v4/projects/{id}/registry/protection/tag/rules", area: "projects", tier: 1, status: "green", mode: "empty", mode_reason: "these govern who may PUBLISH into a registry; a read-only mirror accepts no publishes, so nothing has ever configured a rule here — and real GitLab answers a project with none configured 200 []", mode_reviewed: "2026-09-03", tag: "Projects" }
      - { method: "GET", path: "/api/v4/projects/{id}/registry/repositories", area: "container-registry", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Container registry" }
      - { method: "GET", path: "/api/v4/projects/{id}/registry/repositories/{repository_id}/tags", area: "container-registry", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Container registry" }
      - { method: "GET", path: "/api/v4/projects/{id}/registry/repositories/{repository_id}/tags/{tag_name}", area: "container-registry", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Container registry" }
      - { method: "GET", path: "/api/v4/projects/{id}/relation-imports", area: "project import", tier: 3, status: "deferred", mode: "refuse", mode_reason: "each of these reads reports on an export or import that a WRITE would have started, and writes are refused; GitLab answers 404 for an export nobody requested", mode_reviewed: "2026-09-01", tag: "Project import", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/releases", area: "releases", tier: 1, status: "green", mode: "derive", tag: "Releases" }
      - { method: "GET", path: "/api/v4/projects/{id}/releases/{tag_name}", area: "releases", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Releases" }
      - { method: "GET", path: "/api/v4/projects/{id}/releases/{tag_name}/assets/links", area: "releases", tier: 1, status: "green", mode: "empty", mode_reason: "no release in olympus-labs carries an asset link — canon's release names a tag and a description and nothing is attached to it; GitLab answers `[]` at 200 for a release with no links and its own 404 for a link id. THE LIST HALF: the release TAG must resolve first, so a tag nobody cut is still `404 Release Not Found`. Paginated, per the operation's own `page`/`per_page`. UNGATED: `canon.Release` (packages/canon/src/entities.ts:342) has carried the same nine fields in every generation and not one of them is an attachment. Falsifiable: the `expectsEmpty` entry reds the row the day a release grows a link. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Releases" }
      - { method: "GET", path: "/api/v4/projects/{id}/releases/{tag_name}/assets/links/{link_id}", area: "releases", tier: 1, status: "planned", mode: "refuse", mode_reason: "no release in olympus-labs carries an asset link — canon's release names a tag and a description and nothing is attached to it; GitLab answers `[]` at 200 for a release with no links and its own 404 for a link id. THE LINK-ID HALF: with no link on any release there is no link id to resolve and GitLab's own 404 is the whole answer. UNGATED, for the reason the list half states. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Releases" }
      - { method: "GET", path: "/api/v4/projects/{id}/remote_mirrors", area: "remote mirrors", tier: 3, status: "green", mode: "empty", mode_reason: "nothing here mirrors to or from another host: a remote mirror exists only because someone configured one, and this universe accepts no writes", mode_reviewed: "2026-09-01", tag: "Remote mirrors", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/remote_mirrors/{mirror_id}", area: "remote mirrors", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the collection this id would index is empty in this universe, so the only honest answer is the vendor's own 404", mode_reviewed: "2026-09-01", tag: "Remote mirrors", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/remote_mirrors/{mirror_id}/public_key", area: "remote mirrors", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the collection this id would index is empty in this universe, so the only honest answer is the vendor's own 404", mode_reviewed: "2026-09-01", tag: "Remote mirrors", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/repository_storage_moves", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Storage moves", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/repository_storage_moves/{repository_storage_move_id}", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Storage moves", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/repository/archive", area: "repository-files", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W7): a real archive of the ref's tree, whose members are `reader.treeFiles(commit)` - the same content-addressed blobs `/repository/files/{path}/raw`, `/repository/blobs/{sha}/raw` and `git clone` serve, so a file cannot have one body here and another there. GITLAB'S OWN NAMING, not GitHub's: the single root directory and the download filename are `{project path}-{ref}-{full sha}` from `archive_prefix` (the project's own path segment, the ref as the caller wrote it with slashes flattened, and the sha appended unconditionally because the API passes `append_sha: true`). FORMATS: `tar.gz` (the default - `format ||= 'tar.gz'`), `tar` and `zip` are served, and the three gzip spellings `tgz`/`gz` and any unrecognised `?format=` collapse onto tar.gz exactly as `archive_file_path` does. The five bzip2 spellings answer the coverage 404 naming the format and the reason - node:zlib carries no bzip2 codec and the shared writer has no dependencies - rather than a gzip wearing a `.tar.bz2` name, which is what falling back to the default would have done. A suffix outside GitLab's own `archive_formats_regex` gets GitLab's plain 404, since its route does not match either. `sha` and `ref_type` are answered; `include_lfs_blobs` is answered too and conformance asserts the two values select byte-identical archives, which is true because the file model holds whole file bodies and no LFS pointer; `path` and `exclude_paths` are refused, because a caller who asked for a subfolder and got the whole repository has been answered a different question. Unblocked by the tar/zip writers moving out of packages/renderer-github into `@sandboxapis/archive`, founder-ordered 2026-09-09", mode_reviewed: "2026-09-12", tag: "Repositories" }
      - { method: "GET", path: "/api/v4/projects/{id}/repository/blobs/{sha}", area: "repository-files", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Repositories" }
      - { method: "GET", path: "/api/v4/projects/{id}/repository/blobs/{sha}/raw", area: "repository-files", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Repositories" }
      - { method: "GET", path: "/api/v4/projects/{id}/repository/branches", area: "branches-tags", tier: 1, status: "green", mode: "derive", tag: "Branches" }
      - { method: "GET", path: "/api/v4/projects/{id}/repository/branches/{branch}", area: "branches-tags", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Branches" }
      - { method: "HEAD", path: "/api/v4/projects/{id}/repository/branches/{branch}", area: "branches-tags", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Branches" }
      - { method: "GET", path: "/api/v4/projects/{id}/repository/changelog", area: "repository-files", tier: 1, status: "planned", mode: "refuse", mode_reason: "GitLab renders its changelog template over the commits carrying a `Changelog:` git trailer. Canon writes no trailers — every commit this host serves reports trailers {} — so no commit is ever selectable and there is no changelog to generate; the documented 400 is the refusal. RULED by the founder 2026-09-09", mode_reviewed: "2026-09-09", tag: "Repositories" }
      - { method: "GET", path: "/api/v4/projects/{id}/repository/commits", area: "commits", tier: 1, status: "green", mode: "derive", tag: "Commits" }
      - { method: "GET", path: "/api/v4/projects/{id}/repository/commits/{noteable_id}/discussions", area: "discussions", tier: 1, status: "green", mode: "empty", mode_reason: "no commit in this universe carries a comment — DECISIONS 2026-08-20 [commit-detail] ruled it per endpoint and that ruling stands (the 2026-08-29 entry superseded only its three-verdict bar); GitLab's own answer for a commit with no notes is `[]` at 200. THE LIST HALF: the commit must resolve first (reader.getCommitBySha), so a sha nobody pushed is still GitLab's 404 rather than a cheerful `[]`. UNGATED: packages/canon/src/notes.ts:52 records that hello-17's entity-note domain may not declare a `commit` parent until this ruling is reversed, so no generation of this universe carries a commit note. Falsifiable: the `expectsEmpty` entry reds the row the day one appears. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Discussions" }
      - { method: "GET", path: "/api/v4/projects/{id}/repository/commits/{noteable_id}/discussions/{discussion_id}", area: "discussions", tier: 1, status: "planned", mode: "refuse", mode_reason: "no commit in this universe carries a comment — DECISIONS 2026-08-20 [commit-detail] ruled it per endpoint and that ruling stands (the 2026-08-29 entry superseded only its three-verdict bar); GitLab's own answer for a commit with no notes is `[]` at 200. THE DISCUSSION-ID HALF: with no note on any commit there is no discussion id to resolve, so GitLab's own 404 is the whole answer rather than a 200 over a discussion that does not exist. UNGATED, for the reason the list half states. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Discussions" }
      - { method: "GET", path: "/api/v4/projects/{id}/repository/commits/{noteable_id}/discussions/{discussion_id}/notes", area: "discussions", tier: 1, status: "planned", mode: "refuse", mode_reason: "no commit in this universe carries a comment — DECISIONS 2026-08-20 [commit-detail] ruled it per endpoint and that ruling stands (the 2026-08-29 entry superseded only its three-verdict bar); GitLab's own answer for a commit with no notes is `[]` at 200. THE DISCUSSION-ID HALF: with no note on any commit there is no discussion id to resolve, so GitLab's own 404 is the whole answer rather than a 200 over a discussion that does not exist. UNGATED, for the reason the list half states. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Discussions" }
      - { method: "GET", path: "/api/v4/projects/{id}/repository/commits/{noteable_id}/discussions/{discussion_id}/notes/{note_id}", area: "discussions", tier: 1, status: "planned", mode: "refuse", mode_reason: "no commit in this universe carries a comment — DECISIONS 2026-08-20 [commit-detail] ruled it per endpoint and that ruling stands (the 2026-08-29 entry superseded only its three-verdict bar); GitLab's own answer for a commit with no notes is `[]` at 200. THE DISCUSSION-ID HALF: with no note on any commit there is no discussion id to resolve, so GitLab's own 404 is the whole answer rather than a 200 over a discussion that does not exist. UNGATED, for the reason the list half states. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Discussions" }
      - { method: "GET", path: "/api/v4/projects/{id}/repository/commits/{sha}", area: "commits", tier: 1, status: "green", mode: "derive", tag: "Commits" }
      - { method: "GET", path: "/api/v4/projects/{id}/repository/commits/{sha}/comments", area: "commits", tier: 1, status: "green", mode: "empty", mode_reason: "no commit in this universe carries a comment — DECISIONS 2026-08-20 [commit-detail] ruled it per endpoint and that ruling stands (the 2026-08-29 entry superseded only its three-verdict bar); GitLab's own answer for a commit with no notes is `[]` at 200. THE LIST HALF: the commit must resolve first (reader.getCommitBySha), so a sha nobody pushed is still GitLab's 404 rather than a cheerful `[]`. UNGATED: packages/canon/src/notes.ts:52 records that hello-17's entity-note domain may not declare a `commit` parent until this ruling is reversed, so no generation of this universe carries a commit note. Falsifiable: the `expectsEmpty` entry reds the row the day one appears. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Commits" }
      - { method: "GET", path: "/api/v4/projects/{id}/repository/commits/{sha}/diff", area: "commits", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Commits" }
      - { method: "GET", path: "/api/v4/projects/{id}/repository/commits/{sha}/merge_requests", area: "commits", tier: 1, status: "deviation", mode: "derive", mode_reviewed: "2026-09-01", tag: "Commits" }
      - { method: "GET", path: "/api/v4/projects/{id}/repository/commits/{sha}/refs", area: "commits", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Commits" }
      - { method: "GET", path: "/api/v4/projects/{id}/repository/commits/{sha}/sequence", area: "commits", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Commits" }
      - { method: "GET", path: "/api/v4/projects/{id}/repository/commits/{sha}/signature", area: "commits", tier: 1, status: "planned", mode: "refuse", mode_reason: "no commit or tag in this universe is GPG-signed, and GitLab answers its own 404 'GPG Signature Not Found' for an unsigned object", mode_reviewed: "2026-09-01", tag: "Commits" }
      - { method: "GET", path: "/api/v4/projects/{id}/repository/commits/{sha}/statuses", area: "commits", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Commit statuses" }
      - { method: "GET", path: "/api/v4/projects/{id}/repository/compare", area: "repository-files", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Repositories" }
      - { method: "GET", path: "/api/v4/projects/{id}/repository/contributors", area: "repository-files", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Repositories" }
      - { method: "GET", path: "/api/v4/projects/{id}/repository/diverging_commits", area: "repository-files", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Repositories" }
      - { method: "GET", path: "/api/v4/projects/{id}/repository/files/{file_path}", area: "repository-files", tier: 1, status: "green", mode: "derive", tag: "Files" }
      - { method: "HEAD", path: "/api/v4/projects/{id}/repository/files/{file_path}", area: "repository-files", tier: 1, status: "green", mode: "derive", tag: "Files" }
      - { method: "GET", path: "/api/v4/projects/{id}/repository/files/{file_path}/blame", area: "repository-files", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Files" }
      - { method: "HEAD", path: "/api/v4/projects/{id}/repository/files/{file_path}/blame", area: "repository-files", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Files" }
      - { method: "GET", path: "/api/v4/projects/{id}/repository/files/{file_path}/raw", area: "repository-files", tier: 1, status: "green", mode: "derive", tag: "Files" }
      - { method: "GET", path: "/api/v4/projects/{id}/repository/health", area: "repository-files", tier: 1, status: "planned", mode: "refuse", mode_reason: "this reports Gitaly storage verification for a physical repository; the artifact has no Gitaly behind it", mode_reviewed: "2026-09-01", tag: "Repositories" }
      - { method: "GET", path: "/api/v4/projects/{id}/repository/merge_base", area: "repository-files", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Repositories" }
      - { method: "GET", path: "/api/v4/projects/{id}/repository/tags", area: "branches-tags", tier: 1, status: "green", mode: "derive", tag: "Tags" }
      - { method: "GET", path: "/api/v4/projects/{id}/repository/tags/{tag_name}", area: "branches-tags", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Tags" }
      - { method: "GET", path: "/api/v4/projects/{id}/repository/tags/{tag_name}/signature", area: "branches-tags", tier: 1, status: "planned", mode: "refuse", mode_reason: "no commit or tag in this universe is GPG-signed, and GitLab answers its own 404 'GPG Signature Not Found' for an unsigned object", mode_reviewed: "2026-09-01", tag: "Tags" }
      - { method: "GET", path: "/api/v4/projects/{id}/repository/tree", area: "repository-files", tier: 1, status: "green", mode: "derive", tag: "Repositories" }
      - { method: "GET", path: "/api/v4/projects/{id}/resource_groups", area: "ci resource groups", tier: 3, status: "green", mode: "empty", mode_reason: "no pipeline in olympus-labs serializes on a resource group — every job in canon runs without a concurrency lock; GitLab answers `[]` at 200 for a project with none. THE LIST HALF, served as GitLab's empty page with the pagination headers the operation declares. UNGATED: no generation of this universe takes a concurrency lock on a job, so every registered pin answers this same `[]`. Falsifiable: the `expectsEmpty` conformance entry reds the row the day canon grows one. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "CI resource groups", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/resource_groups/{key}", area: "ci resource groups", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no pipeline in olympus-labs serializes on a resource group — every job in canon runs without a concurrency lock; GitLab answers `[]` at 200 for a project with none. THE NAMED HALF: no name resolves over a collection that is empty, so GitLab's own 404 is the whole answer — `[]` here would assert that the thing exists and holds nothing. UNGATED: no generation of this universe takes a concurrency lock on a job, so the 404 is true on every artifact. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "CI resource groups", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/resource_groups/{key}/current_job", area: "ci resource groups", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no pipeline in olympus-labs serializes on a resource group — every job in canon runs without a concurrency lock; GitLab answers `[]` at 200 for a project with none. THE NAMED HALF: no name resolves over a collection that is empty, so GitLab's own 404 is the whole answer — `[]` here would assert that the thing exists and holds nothing. UNGATED: no generation of this universe takes a concurrency lock on a job, so the 404 is true on every artifact. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "CI resource groups", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/resource_groups/{key}/upcoming_jobs", area: "ci resource groups", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no pipeline in olympus-labs serializes on a resource group — every job in canon runs without a concurrency lock; GitLab answers `[]` at 200 for a project with none. THE NAMED HALF: no name resolves over a collection that is empty, so GitLab's own 404 is the whole answer — `[]` here would assert that the thing exists and holds nothing. UNGATED: no generation of this universe takes a concurrency lock on a job, so the 404 is true on every artifact. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "CI resource groups", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/runners", area: "runners", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon's jobs ran on nothing; needs a Runner the job table can point at", mode_reviewed: "2026-09-01", tag: "Runners" }
      - { method: "GET", path: "/api/v4/projects/{id}/secure_files", area: "secure files", tier: 3, status: "green", mode: "empty", mode_reason: "olympus-labs stores no CI secure file — canon holds no secret VALUE and no uploaded secret FILE; GitLab answers `[]` at 200 for a project with none. THE LIST HALF, served as GitLab's empty page with the pagination headers the operation declares. UNGATED: no generation of this universe stores a secret VALUE or an uploaded secret FILE — hello-19's `ci_binding` stores secret NAMES and dates and has no column that could hold a value, which is asserted as SQL rather than reviewed — so every registered pin answers this same `[]`, and so does every generation after it. Falsifiable: the `expectsEmpty` conformance entry reds the row the day canon grows one. RULED by the founder 2026-09-12; the clause was narrowed on 2026-09-12 in hello-19 wave W-b (founder call F4) from the broader claim that canon holds no secret material of any kind — same conclusion, same mode, same review date, and a narrower fact that stays permanently checkable now that a generation stores secret NAMES", mode_reviewed: "2026-09-12", tag: "Secure files", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/secure_files/{secure_file_id}", area: "secure files", tier: 3, status: "deferred", mode: "refuse", mode_reason: "olympus-labs stores no CI secure file — canon holds no secret VALUE and no uploaded secret FILE; GitLab answers `[]` at 200 for a project with none. THE NAMED HALF: no name resolves over a collection that is empty, so GitLab's own 404 is the whole answer — `[]` here would assert that the thing exists and holds nothing. UNGATED: no generation of this universe stores a secret VALUE or an uploaded secret FILE — hello-19's `ci_binding` stores secret NAMES and dates and has no column that could hold a value, which is asserted as SQL rather than reviewed — so the 404 is true on every artifact. RULED by the founder 2026-09-12; the clause was narrowed on 2026-09-12 in hello-19 wave W-b (founder call F4) from the broader claim that canon holds no secret material of any kind — same conclusion, same mode, same review date, and a narrower fact that stays permanently checkable now that a generation stores secret NAMES", mode_reviewed: "2026-09-12", tag: "Secure files", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/secure_files/{secure_file_id}/download", area: "secure files", tier: 3, status: "deferred", mode: "refuse", mode_reason: "olympus-labs stores no CI secure file — canon holds no secret VALUE and no uploaded secret FILE; GitLab answers `[]` at 200 for a project with none. THE NAMED HALF: no name resolves over a collection that is empty, so GitLab's own 404 is the whole answer — `[]` here would assert that the thing exists and holds nothing. UNGATED: no generation of this universe stores a secret VALUE or an uploaded secret FILE — hello-19's `ci_binding` stores secret NAMES and dates and has no column that could hold a value, which is asserted as SQL rather than reviewed — so the 404 is true on every artifact. RULED by the founder 2026-09-12; the clause was narrowed on 2026-09-12 in hello-19 wave W-b (founder call F4) from the broader claim that canon holds no secret material of any kind — same conclusion, same mode, same review date, and a narrower fact that stays permanently checkable now that a generation stores secret NAMES", mode_reviewed: "2026-09-12", tag: "Secure files", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/security_settings", area: "projects", tier: 1, status: "planned", mode: "generate", mode_reason: "canon has no SecurityFinding/SbomComponent/Attestation; a scanning org has findings", mode_reviewed: "2026-09-01", tag: "Projects" }
      - { method: "GET", path: "/api/v4/projects/{id}/service_accounts", area: "service accounts", tier: 3, status: "green", mode: "empty", mode_reason: "every actor in olympus-labs is a person on the roster — canon mints no bot principal, and a service account served here would be a member no other host lists (invariant #5); GitLab answers `[]` at 200 for a group with none. THE LIST HALF, served as GitLab's empty page with the pagination headers the operation declares. UNGATED: canon has no `ServiceAccount` in any generation — hello-17 dropped the federation domain that would have introduced one, so every registered pin answers this same `[]`. Falsifiable: the `expectsEmpty` conformance entry reds the row the day canon grows one. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Service accounts", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/service_accounts/{user_id}/personal_access_tokens", area: "deploy-keys-tokens", tier: 3, status: "deferred", mode: "refuse", mode_reason: "every actor in olympus-labs is a person on the roster — canon mints no bot principal, and a service account served here would be a member no other host lists (invariant #5); GitLab answers `[]` at 200 for a group with none. THE NAMED HALF: `{user_id}` names a service account, and no service account exists to be named — so this operation never reaches a token list to be empty of and GitLab's own 404 is the whole answer. UNGATED: canon has no `ServiceAccount` in any generation — hello-17 dropped the federation domain that would have introduced one. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Access tokens" }
      - { method: "GET", path: "/api/v4/projects/{id}/services", area: "integrations", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Integration; this universe literally has a Jira and a Slack to be integrated with", mode_reviewed: "2026-09-01", tag: "Integrations", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/services/{slug}", area: "integrations", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Integration; this universe literally has a Jira and a Slack to be integrated with", mode_reviewed: "2026-09-01", tag: "Integrations", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/share_locations", area: "projects", tier: 1, status: "deviation", mode: "derive", mode_reason: "the groups a project can be invited to, excluding the one that already owns it. The subgroup qualifies from hello-16. Unpaginated: the vendored document declares no page/per_page on this operation. Older pins still answer the empty list. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", tag: "Projects" }
      - { method: "GET", path: "/api/v4/projects/{id}/snapshot", area: "project snapshots", tier: 3, status: "deferred", mode: "refuse", mode_reason: "each of these reads reports on an export or import that a WRITE would have started, and writes are refused; GitLab answers 404 for an export nobody requested", mode_reviewed: "2026-09-01", tag: "Project snapshots", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/snippets", area: "snippets", tier: 3, status: "green", mode: "empty", mode_reason: "no snippet exists in this organization — every shared file in olympus-labs lives in the parthenon repository and no persona has ever posted a snippet; GitLab answers `[]` at 200 for a snippet list and its own 404 for a snippet id that names nothing. THE LIST HALF, served as GitLab's empty page with the pagination headers the operation declares (`page`/`per_page`). UNGATED: canon has no `Snippet` entity in any generation — packages/canon/src/avatars-reactions.ts:188 names it as the blocker the hello-15 reaction domain could not answer — so every registered pin answers this same `[]`. Falsifiable: the `expectsEmpty` conformance entry reds the row the day canon grows a snippet. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Snippets" }
      - { method: "GET", path: "/api/v4/projects/{id}/snippets/{noteable_id}/discussions", area: "discussions", tier: 1, status: "planned", mode: "refuse", mode_reason: "no snippet exists in this organization — every shared file in olympus-labs lives in the parthenon repository and no persona has ever posted a snippet; GitLab answers `[]` at 200 for a snippet list and its own 404 for a snippet id that names nothing. THE ID HALF: no snippet id resolves, so this operation never reaches a collection to be empty of and GitLab's own 404 is the whole answer — `[]` on a snippet's award-emoji or note list would assert that the snippet exists and holds nothing. UNGATED: canon has no `Snippet` in any generation, so the 404 is true on every artifact. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Discussions" }
      - { method: "GET", path: "/api/v4/projects/{id}/snippets/{noteable_id}/discussions/{discussion_id}", area: "discussions", tier: 1, status: "planned", mode: "refuse", mode_reason: "no snippet exists in this organization — every shared file in olympus-labs lives in the parthenon repository and no persona has ever posted a snippet; GitLab answers `[]` at 200 for a snippet list and its own 404 for a snippet id that names nothing. THE ID HALF: no snippet id resolves, so this operation never reaches a collection to be empty of and GitLab's own 404 is the whole answer — `[]` on a snippet's award-emoji or note list would assert that the snippet exists and holds nothing. UNGATED: canon has no `Snippet` in any generation, so the 404 is true on every artifact. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Discussions" }
      - { method: "GET", path: "/api/v4/projects/{id}/snippets/{noteable_id}/discussions/{discussion_id}/notes", area: "discussions", tier: 1, status: "planned", mode: "refuse", mode_reason: "no snippet exists in this organization — every shared file in olympus-labs lives in the parthenon repository and no persona has ever posted a snippet; GitLab answers `[]` at 200 for a snippet list and its own 404 for a snippet id that names nothing. THE ID HALF: no snippet id resolves, so this operation never reaches a collection to be empty of and GitLab's own 404 is the whole answer — `[]` on a snippet's award-emoji or note list would assert that the snippet exists and holds nothing. UNGATED: canon has no `Snippet` in any generation, so the 404 is true on every artifact. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Discussions" }
      - { method: "GET", path: "/api/v4/projects/{id}/snippets/{noteable_id}/discussions/{discussion_id}/notes/{note_id}", area: "discussions", tier: 1, status: "planned", mode: "refuse", mode_reason: "no snippet exists in this organization — every shared file in olympus-labs lives in the parthenon repository and no persona has ever posted a snippet; GitLab answers `[]` at 200 for a snippet list and its own 404 for a snippet id that names nothing. THE ID HALF: no snippet id resolves, so this operation never reaches a collection to be empty of and GitLab's own 404 is the whole answer — `[]` on a snippet's award-emoji or note list would assert that the snippet exists and holds nothing. UNGATED: canon has no `Snippet` in any generation, so the 404 is true on every artifact. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Discussions" }
      - { method: "GET", path: "/api/v4/projects/{id}/snippets/{noteable_id}/notes", area: "notes", tier: 1, status: "planned", mode: "refuse", mode_reason: "no snippet exists in this organization — every shared file in olympus-labs lives in the parthenon repository and no persona has ever posted a snippet; GitLab answers `[]` at 200 for a snippet list and its own 404 for a snippet id that names nothing. THE ID HALF: no snippet id resolves, so this operation never reaches a collection to be empty of and GitLab's own 404 is the whole answer — `[]` on a snippet's award-emoji or note list would assert that the snippet exists and holds nothing. UNGATED: canon has no `Snippet` in any generation, so the 404 is true on every artifact. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Notes" }
      - { method: "GET", path: "/api/v4/projects/{id}/snippets/{noteable_id}/notes/{note_id}", area: "notes", tier: 1, status: "planned", mode: "refuse", mode_reason: "no snippet exists in this organization — every shared file in olympus-labs lives in the parthenon repository and no persona has ever posted a snippet; GitLab answers `[]` at 200 for a snippet list and its own 404 for a snippet id that names nothing. THE ID HALF: no snippet id resolves, so this operation never reaches a collection to be empty of and GitLab's own 404 is the whole answer — `[]` on a snippet's award-emoji or note list would assert that the snippet exists and holds nothing. UNGATED: canon has no `Snippet` in any generation, so the 404 is true on every artifact. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Notes" }
      - { method: "GET", path: "/api/v4/projects/{id}/snippets/{snippet_id}", area: "snippets", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no snippet exists in this organization — every shared file in olympus-labs lives in the parthenon repository and no persona has ever posted a snippet; GitLab answers `[]` at 200 for a snippet list and its own 404 for a snippet id that names nothing. THE ID HALF: no snippet id resolves, so this operation never reaches a collection to be empty of and GitLab's own 404 is the whole answer — `[]` on a snippet's award-emoji or note list would assert that the snippet exists and holds nothing. UNGATED: canon has no `Snippet` in any generation, so the 404 is true on every artifact. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Snippets" }
      - { method: "GET", path: "/api/v4/projects/{id}/snippets/{snippet_id}/award_emoji", area: "award emoji", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no snippet exists in this organization — every shared file in olympus-labs lives in the parthenon repository and no persona has ever posted a snippet; GitLab answers `[]` at 200 for a snippet list and its own 404 for a snippet id that names nothing. THE ID HALF: no snippet id resolves, so this operation never reaches a collection to be empty of and GitLab's own 404 is the whole answer — `[]` on a snippet's award-emoji or note list would assert that the snippet exists and holds nothing. UNGATED: canon has no `Snippet` in any generation, so the 404 is true on every artifact. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Award emoji", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/snippets/{snippet_id}/award_emoji/{award_id}", area: "award emoji", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no snippet exists in this organization — every shared file in olympus-labs lives in the parthenon repository and no persona has ever posted a snippet; GitLab answers `[]` at 200 for a snippet list and its own 404 for a snippet id that names nothing. THE ID HALF: no snippet id resolves, so this operation never reaches a collection to be empty of and GitLab's own 404 is the whole answer — `[]` on a snippet's award-emoji or note list would assert that the snippet exists and holds nothing. UNGATED: canon has no `Snippet` in any generation, so the 404 is true on every artifact. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Award emoji", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/snippets/{snippet_id}/files/{ref}/{file_path}/raw", area: "snippets", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no snippet exists in this organization — every shared file in olympus-labs lives in the parthenon repository and no persona has ever posted a snippet; GitLab answers `[]` at 200 for a snippet list and its own 404 for a snippet id that names nothing. THE ID HALF: no snippet id resolves, so this operation never reaches a collection to be empty of and GitLab's own 404 is the whole answer — `[]` on a snippet's award-emoji or note list would assert that the snippet exists and holds nothing. UNGATED: canon has no `Snippet` in any generation, so the 404 is true on every artifact. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Snippets" }
      - { method: "GET", path: "/api/v4/projects/{id}/snippets/{snippet_id}/notes/{note_id}/award_emoji", area: "award emoji", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no snippet exists in this organization — every shared file in olympus-labs lives in the parthenon repository and no persona has ever posted a snippet; GitLab answers `[]` at 200 for a snippet list and its own 404 for a snippet id that names nothing. THE ID HALF: no snippet id resolves, so this operation never reaches a collection to be empty of and GitLab's own 404 is the whole answer — `[]` on a snippet's award-emoji or note list would assert that the snippet exists and holds nothing. UNGATED: canon has no `Snippet` in any generation, so the 404 is true on every artifact. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Award emoji", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/snippets/{snippet_id}/notes/{note_id}/award_emoji/{award_id}", area: "award emoji", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no snippet exists in this organization — every shared file in olympus-labs lives in the parthenon repository and no persona has ever posted a snippet; GitLab answers `[]` at 200 for a snippet list and its own 404 for a snippet id that names nothing. THE ID HALF: no snippet id resolves, so this operation never reaches a collection to be empty of and GitLab's own 404 is the whole answer — `[]` on a snippet's award-emoji or note list would assert that the snippet exists and holds nothing. UNGATED: canon has no `Snippet` in any generation, so the 404 is true on every artifact. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Award emoji", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/snippets/{snippet_id}/raw", area: "snippets", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no snippet exists in this organization — every shared file in olympus-labs lives in the parthenon repository and no persona has ever posted a snippet; GitLab answers `[]` at 200 for a snippet list and its own 404 for a snippet id that names nothing. THE ID HALF: no snippet id resolves, so this operation never reaches a collection to be empty of and GitLab's own 404 is the whole answer — `[]` on a snippet's award-emoji or note list would assert that the snippet exists and holds nothing. UNGATED: canon has no `Snippet` in any generation, so the 404 is true on every artifact. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Snippets" }
      - { method: "GET", path: "/api/v4/projects/{id}/snippets/{snippet_id}/user_agent_detail", area: "snippets", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab exposes user-agent detail to instance administrators for abuse reports only; a non-admin token gets 403", mode_reviewed: "2026-09-01", tag: "Snippets" }
      - { method: "GET", path: "/api/v4/projects/{id}/starrers", area: "projects", tier: 1, status: "planned", mode: "generate", mode_reason: "canon has no Star; the founder ruled stars generated on both hosts so a starred repo is the same repo on GitHub and GitLab", mode_reviewed: "2026-09-01", tag: "Projects" }
      - { method: "GET", path: "/api/v4/projects/{id}/statistics", area: "projects", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Projects" }
      - { method: "GET", path: "/api/v4/projects/{id}/storage", area: "projects", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Projects" }
      - { method: "GET", path: "/api/v4/projects/{id}/templates/{type}", area: "project templates", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W8) (hello-16 `refCatalogs`): reader.listLicenses()/listGitignoreTemplates() over `license_catalog` (13 rows, bodies included) and `gitignore_template` (163 rows, source included) — the SAME two compile-time tables GitHub's /licenses and /gitignore/templates already serve, which is what makes a licence fetched through either host the same licence (invariant #5). GENERATION-GATED and `[]` is not an option: an artifact without the catalogs answers the template-catalog generation gap, because `[]` here would say GitLab bundles no licence templates — a claim about the HOST rather than about this organization, and a false one. licence: FACTUAL/CC0 — the licence texts are the licences themselves and the ignore-file templates are github/gitignore's CC0-1.0 corpus, the same grant coverage/reviews/2026-09-09-hello-15-stale-reasons-git-hosts.md records for the GitHub twins. The project-scoped read is the SAME catalog, and conformance asserts the two lists are identical rather than merely similar. TWO OF THE SIX DECLARED TYPES ANSWER: `licenses` and `gitignores`, the two canon carries a catalog for. `dockerfiles`, `gitlab_ci_ymls`, `issues` and `merge_requests` answer the COVERAGE 404 naming the manifest rather than `[]` — an empty list would be a claim about GitLab's bundled set, or about this project's absent `.gitlab/issue_templates` directory, that nothing here checked (invariant #4). Conformance drives all four and asserts the 404", mode_reviewed: "2026-09-12", tag: "Project templates", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/templates/{type}/{name}", area: "project templates", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W8) (hello-16 `refCatalogs`): reader.license(key)/gitignoreTemplate(name) over `license_catalog` (13 rows, bodies included) and `gitignore_template` (163 rows, source included) — the SAME two compile-time tables GitHub's /licenses and /gitignore/templates already serve, which is what makes a licence fetched through either host the same licence (invariant #5). GENERATION-GATED and `[]` is not an option: an artifact without the catalogs answers the template-catalog generation gap, because `[]` here would say GitLab bundles no licence templates — a claim about the HOST rather than about this organization, and a false one. licence: FACTUAL/CC0 — the licence texts are the licences themselves and the ignore-file templates are github/gitignore's CC0-1.0 corpus, the same grant coverage/reviews/2026-09-09-hello-15-stale-reasons-git-hosts.md records for the GitHub twins. BYTE-IDENTICAL to the instance-scoped read of the same template, which conformance compares directly: one catalog, two addresses. The vendored document types this operation's 200 as `APIEntitiesLicense` for EVERY type, which is true of one of the six — real GitLab presents `Entities::Template` for an ignore file, and invariant #2 mirrors the provider rather than its documentation. The same four types that are not covered on the collection are not covered here", mode_reviewed: "2026-09-12", tag: "Project templates", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/terraform/state_protection_rules", area: "projects", tier: 1, status: "green", mode: "empty", mode_reason: "these govern who may PUBLISH into a registry; a read-only mirror accepts no publishes, so nothing has ever configured a rule here — and real GitLab answers a project with none configured 200 []", mode_reviewed: "2026-09-03", tag: "Projects" }
      - { method: "GET", path: "/api/v4/projects/{id}/terraform/state/{name}", area: "terraform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "state describes real infrastructure the sandbox does not have; GitLab 404s a state name nobody wrote, and writes are refused", mode_reviewed: "2026-09-01", tag: "Terraform", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/terraform/state/{name}/versions/{serial}", area: "terraform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "state describes real infrastructure the sandbox does not have; GitLab 404s a state name nobody wrote, and writes are refused", mode_reviewed: "2026-09-01", tag: "Terraform", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/transfer_locations", area: "projects", tier: 1, status: "green", mode: "derive", mode_reason: "the namespaces a project can be moved into, excluding its current parent. From hello-16 there is one that qualifies - the subgroup - so reader.listNamespaces() answers a real row where the 2026-09-09 ruling had nowhere to point. Older pins still answer the empty list. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", tag: "Projects" }
      - { method: "GET", path: "/api/v4/projects/{id}/triggers", area: "variables", tier: 3, status: "deferred", mode: "generate", mode_reason: "RE-SCOPED 2026-09-09: the 23-row CiVariable+PipelineSchedule+ResourceGroup+SecureFile+FreezePeriod clique was hiding a solved fifth — hello-15's canon.WorkflowSchedule answers the PIPELINE SCHEDULES (see /api/v4/projects/{id}/pipeline_schedules). A JOB TOKEN is not: the scope rows are the cross-project trust list a CI job's token may reach, and the trigger rows are the tokens that start a pipeline from outside. canon stores no token (the PagerDuty routing-key rule, DECISIONS 2026-09-03) and this universe holds one project, so neither the allowlist nor the trigger has anything to point at. New canon entities JobTokenScope and PipelineTrigger", mode_reviewed: "2026-09-09", tag: "CI triggers" }
      - { method: "GET", path: "/api/v4/projects/{id}/triggers/{trigger_id}", area: "variables", tier: 3, status: "deferred", mode: "generate", mode_reason: "RE-SCOPED 2026-09-09: the 23-row CiVariable+PipelineSchedule+ResourceGroup+SecureFile+FreezePeriod clique was hiding a solved fifth — hello-15's canon.WorkflowSchedule answers the PIPELINE SCHEDULES (see /api/v4/projects/{id}/pipeline_schedules). A JOB TOKEN is not: the scope rows are the cross-project trust list a CI job's token may reach, and the trigger rows are the tokens that start a pipeline from outside. canon stores no token (the PagerDuty routing-key rule, DECISIONS 2026-09-03) and this universe holds one project, so neither the allowlist nor the trigger has anything to point at. New canon entities JobTokenScope and PipelineTrigger", mode_reviewed: "2026-09-09", tag: "CI triggers" }
      - { method: "GET", path: "/api/v4/projects/{id}/uploads", area: "projects", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-18): APIEntitiesMarkdownUploadAdmin over the files hanging off THIS PROJECT'S OWN RECORDS — its issues, those issues' comments and its merge requests — which is a JOIN rather than a column, because decisions/2026-09-12-1148 declines a `repo` parent in as many words: a row claiming a project upload with no record behind it would be a file nobody uploaded. Newest first, which is the operation's own stated order, tie-broken on the canonical id so the list paginates identically on every request. `size` is the artifact's MEASURED length, computed at compile from the body rather than drawn, so the list and the download cannot describe different files; `uploaded_by` is APIEntitiesUserSafe and every uploader resolves to a person this host serves. THE ALERT METRIC IMAGES ARE DELIBERATELY NOT IN THIS LIST and conformance asserts their absence: GitLab keeps them in its system store (/uploads/-/system/alert_metric_image/…, which is the vendored component's own example path), not among a project's markdown uploads, and serving one file at both addresses would assert two uploads where canon records one. Gated on hasAttachmentParents(); an older artifact answers the named hello-18 upload gap rather than [], because [] there would say nobody here ever attached a file — false of the story every generation tells, where only the PARENT column was missing", mode_reviewed: "2026-09-12", tag: "Projects" }
      - { method: "GET", path: "/api/v4/projects/{id}/uploads/{secret}/{filename}", area: "projects", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-18): the FILE. The vendored operation declares no response schema at all, because the body is the bytes: this route answers the artifact's own attachment.body verbatim, with the artifact's own content_type and `Content-Disposition: attachment` naming the file. The disposition is `attachment` for every kind rather than a branch this host guesses at — GitLab serves an upload inline only for a type on its own safe list, and image/svg+xml, which every image in this canon carries, is explicitly not on it because an SVG can carry script. Conformance re-reads the artifact row and asserts the served bytes are identical to it and that their length is the `size` the list advertised. THE `secret` IS THE FILE'S OWN DIGEST, first 32 characters. GitLab mints a 32-character hex token per upload and canon mints none; an invented one would be a value no client could cross-check, while the first half of attachment.sha256 — measured from the body at compile — is 32 hex characters, is a pure function of the bytes it addresses, and is reproducible by any caller that has downloaded the file. Conformance asserts the secret address and the id address serve the same bytes, and that a secret which is not this file's digest is GitLab's own 404. The filename must match too: a right secret with a wrong name addresses nothing. Gated on hasAttachmentParents(); an older artifact answers the named hello-18 upload gap", mode_reviewed: "2026-09-12", tag: "Projects" }
      - { method: "GET", path: "/api/v4/projects/{id}/uploads/{upload_id}", area: "projects", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-18): the FILE. The vendored operation declares no response schema at all, because the body is the bytes: this route answers the artifact's own attachment.body verbatim, with the artifact's own content_type and `Content-Disposition: attachment` naming the file. The disposition is `attachment` for every kind rather than a branch this host guesses at — GitLab serves an upload inline only for a type on its own safe list, and image/svg+xml, which every image in this canon carries, is explicitly not on it because an SVG can carry script. Conformance re-reads the artifact row and asserts the served bytes are identical to it and that their length is the `size` the list advertised. The id is gitlabId(attachment.id), the same id the list publishes, and an id this project's records do not carry is GitLab's own 404 — a group upload's id included. Gated on hasAttachmentParents(); an older artifact answers the named hello-18 upload gap", mode_reviewed: "2026-09-12", tag: "Projects" }
      - { method: "GET", path: "/api/v4/projects/{id}/users", area: "projects", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Projects" }
      - { method: "GET", path: "/api/v4/projects/{id}/variables", area: "variables", tier: 3, status: "green", mode: "derive", mode_reason: "the project's CI/CD variables, off reader.repoCiBindings(repo, 'pipeline') followed by each deployment environment's rows through reader.environmentCiBindings(repo, name), published under `environment_scope`. THE ENVIRONMENT ROWS BELONG IN THIS LIST because GitLab has no per-environment variable endpoint at all — environment scoping is a FIELD on the project variable, and the by-key operation's own description (if there are multiple variables with the same key, use filter to select the correct environment_scope) is the vendored document describing exactly this case. The group's rows are NOT here — GitLab merges those into a JOB's environment, not into this endpoint — and neither is the coding agent's, which is the audience scoping every ci_binding accessor is written to enforce. SERVED 2026-09-12 (hello-19 `ciBindings`): the 2026-09-09 re-scope asked for a variable table and named the constraint that would make one honest — a masked value is a secret canon stores none of. hello-19's `ci_binding` is that table, built on exactly that constraint: one row, one `masked` boolean, and NO VALUE IN ANY COLUMN on a masked row (`compiler/src/hello19.test.ts` asserts `COUNT(*) WHERE masked = 1 AND value IS NOT NULL` is 0 on every compiled artifact). A MASKED BINDING RENDERS `hidden: true` AND SHIPS NO `value` KEY, which is GitLab's own vocabulary rather than a convenience: `masked` means blanked out of JOB LOGS and `hidden` (created as `masked_and_hidden`) means THE API NEVER RETURNS THE VALUE, so `masked: true, hidden: false` with the key dropped would be a shape real GitLab never sends. An unmasked binding's `value` is the artifact row `ci_binding.value_source` names — the collector's endpoint, the default branch, the orb document's tree path — resolved at compile time, so the setting and the thing it configures cannot drift apart. `variable_type` is `env_var` on every row, which agrees with /api/v4/projects/{id}/secure_files being ruled empty: a `file` variable IS a secure file. `raw` and `description` are OMITTED rather than defaulted — neither is required by APIEntitiesCiVariable and neither is a fact canon holds (the depth-hooks.ts rule, one wave earlier). Conformance drives each row against the vendored schema AND against the reader accessor the renderer must have used, walks the pages with the headers asserted, and fails if a masked row ever carries a value. Gated on hasCiBindings(); an older artifact answers the named hello-19 CI-variable gap, because [] there would say this organization configures its pipelines with nothing while the same artifact publishes a CI document, a nightly schedule and deployments to two environments", mode_reviewed: "2026-09-12", tag: "CI variables" }
      - { method: "GET", path: "/api/v4/projects/{id}/variables/{key}", area: "variables", tier: 3, status: "green", mode: "derive", mode_reason: "the same project variable by key, with `filter[environment_scope]` honoured as a real selector — four of this project's variables share a key with another (DEPLOY_ENVIRONMENT and ENVIRONMENT_DEPLOY_TOKEN, once per environment), which is the case the operation's description tells a caller to use the filter for, and conformance drives every duplicated key through every scope it exists in plus one it does not. GitLab's own `404 Variable Not Found` for an unknown key, `%ZZ` included. SERVED 2026-09-12 (hello-19 `ciBindings`): the 2026-09-09 re-scope asked for a variable table and named the constraint that would make one honest — a masked value is a secret canon stores none of. hello-19's `ci_binding` is that table, built on exactly that constraint: one row, one `masked` boolean, and NO VALUE IN ANY COLUMN on a masked row (`compiler/src/hello19.test.ts` asserts `COUNT(*) WHERE masked = 1 AND value IS NOT NULL` is 0 on every compiled artifact). A MASKED BINDING RENDERS `hidden: true` AND SHIPS NO `value` KEY, which is GitLab's own vocabulary rather than a convenience: `masked` means blanked out of JOB LOGS and `hidden` (created as `masked_and_hidden`) means THE API NEVER RETURNS THE VALUE, so `masked: true, hidden: false` with the key dropped would be a shape real GitLab never sends. An unmasked binding's `value` is the artifact row `ci_binding.value_source` names — the collector's endpoint, the default branch, the orb document's tree path — resolved at compile time, so the setting and the thing it configures cannot drift apart. `variable_type` is `env_var` on every row, which agrees with /api/v4/projects/{id}/secure_files being ruled empty: a `file` variable IS a secure file. `raw` and `description` are OMITTED rather than defaulted — neither is required by APIEntitiesCiVariable and neither is a fact canon holds (the depth-hooks.ts rule, one wave earlier). Conformance drives each row against the vendored schema AND against the reader accessor the renderer must have used, walks the pages with the headers asserted, and fails if a masked row ever carries a value. Gated on hasCiBindings(); an older artifact answers the named hello-19 CI-variable gap, because [] there would say this organization configures its pipelines with nothing while the same artifact publishes a CI document, a nightly schedule and deployments to two environments", mode_reviewed: "2026-09-12", tag: "CI variables" }
      - { method: "GET", path: "/api/v4/projects/{id}/vulnerabilities", area: "vulnerabilities", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no SecurityFinding/SbomComponent/Attestation; a scanning org has findings", mode_reviewed: "2026-09-01", tag: "Vulnerabilities", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/vulnerabilities/{noteable_id}/notes", area: "notes", tier: 1, status: "planned", mode: "refuse", mode_reason: "no vulnerability exists in this organization — canon carries no SecurityFinding, so no vulnerability id resolves, and GitLab's own 404 for an unknown vulnerability is the whole answer. BOTH HALVES REFUSE rather than one of them answering `[]`: the note list hangs off a `{noteable_id}` that names a VULNERABILITY, and a 200 `[]` there would assert the vulnerability exists and nobody commented on it. UNGATED: packages/canon/src/notes.ts:52 records `SecurityFinding` as the entity hello-17's entity-note domain is still missing, so no generation of this universe holds one. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Notes" }
      - { method: "GET", path: "/api/v4/projects/{id}/vulnerabilities/{noteable_id}/notes/{note_id}", area: "notes", tier: 1, status: "planned", mode: "refuse", mode_reason: "no vulnerability exists in this organization — canon carries no SecurityFinding, so no vulnerability id resolves, and GitLab's own 404 for an unknown vulnerability is the whole answer. BOTH HALVES REFUSE rather than one of them answering `[]`: the note list hangs off a `{noteable_id}` that names a VULNERABILITY, and a 200 `[]` there would assert the vulnerability exists and nobody commented on it. UNGATED: packages/canon/src/notes.ts:52 records `SecurityFinding` as the entity hello-17's entity-note domain is still missing, so no generation of this universe holds one. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Notes" }
      - { method: "GET", path: "/api/v4/projects/{id}/vulnerability_findings", area: "vulnerabilities", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no SecurityFinding/SbomComponent/Attestation; a scanning org has findings", mode_reviewed: "2026-09-01", tag: "Vulnerabilities", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/projects/{id}/wiki_pages/{noteable_id}/notes", area: "notes", tier: 1, status: "planned", mode: "refuse", mode_reason: "olympus-labs documents its services in the parthenon repository, not in a wiki — no WikiPage exists at project or group scope; GitLab answers `[]` at 200 for the wiki list and its own 404 for a slug that names nothing. THE SLUG/PAGE-ID HALF: no slug and no wiki_page_meta_id resolves, so GitLab's own 404 is the whole answer — a 200 `[]` on a wiki page's note list would assert that the page exists and nobody commented on it. UNGATED: canon has no WikiPage in any generation. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Notes" }
      - { method: "GET", path: "/api/v4/projects/{id}/wiki_pages/{noteable_id}/notes/{note_id}", area: "notes", tier: 1, status: "planned", mode: "refuse", mode_reason: "olympus-labs documents its services in the parthenon repository, not in a wiki — no WikiPage exists at project or group scope; GitLab answers `[]` at 200 for the wiki list and its own 404 for a slug that names nothing. THE SLUG/PAGE-ID HALF: no slug and no wiki_page_meta_id resolves, so GitLab's own 404 is the whole answer — a 200 `[]` on a wiki page's note list would assert that the page exists and nobody commented on it. UNGATED: canon has no WikiPage in any generation. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Notes" }
      - { method: "GET", path: "/api/v4/projects/{id}/wikis", area: "wikis", tier: 3, status: "green", mode: "empty", mode_reason: "olympus-labs documents its services in the parthenon repository, not in a wiki — no WikiPage exists at project or group scope; GitLab answers `[]` at 200 for the wiki list and its own 404 for a slug that names nothing. THE LIST HALF, served UNPAGINATED because the vendored operation declares only `id` and `with_content` — printing pagination headers on an operation GitLab does not paginate would break invariant #2 in the name of consistency. Both container ids answer it: the document says \"for a group\" and restricts the operation to no particular one, so the subgroup is not denied a family this host lists it under (invariant #5). UNGATED: canon has no WikiPage in any generation. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Wikis" }
      - { method: "GET", path: "/api/v4/projects/{id}/wikis/{slug}", area: "wikis", tier: 3, status: "deferred", mode: "refuse", mode_reason: "olympus-labs documents its services in the parthenon repository, not in a wiki — no WikiPage exists at project or group scope; GitLab answers `[]` at 200 for the wiki list and its own 404 for a slug that names nothing. THE SLUG/PAGE-ID HALF: no slug and no wiki_page_meta_id resolves, so GitLab's own 404 is the whole answer — a 200 `[]` on a wiki page's note list would assert that the page exists and nobody commented on it. UNGATED: canon has no WikiPage in any generation. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Wikis" }
      - { method: "GET", path: "/api/v4/projects/{project_id}/packages/nuget/v2/FindPackagesById\\(\\)", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: NuGet" }
      - { method: "GET", path: "/api/v4/projects/{project_id}/packages/nuget/v2/Packages\\(\\)", area: "packages", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Packages: NuGet" }
      - { method: "GET", path: "/api/v4/registry/repositories/{id}", area: "container-registry", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no Package/PackageFile; a simulated org publishes packages and container images", mode_reviewed: "2026-09-01", tag: "Container registry" }
      - { method: "GET", path: "/api/v4/runner_controllers", area: "runners", tier: 3, status: "deferred", mode: "refuse", mode_reason: "runner managers, controllers, tokens and router discovery describe physical CI machines and their credentials, not the org; GitLab restricts them to admins", mode_reviewed: "2026-09-01", tag: "Runners" }
      - { method: "GET", path: "/api/v4/runner_controllers/{id}", area: "runner controllers", tier: 3, status: "deferred", mode: "refuse", mode_reason: "runner managers, controllers, tokens and router discovery describe physical CI machines and their credentials, not the org; GitLab restricts them to admins", mode_reviewed: "2026-09-01", tag: "Runner controllers", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/runner_controllers/{id}/scopes", area: "runner controllers", tier: 3, status: "deferred", mode: "refuse", mode_reason: "runner managers, controllers, tokens and router discovery describe physical CI machines and their credentials, not the org; GitLab restricts them to admins", mode_reviewed: "2026-09-01", tag: "Runner controllers", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/runner_controllers/{runner_controller_id}/tokens", area: "runners", tier: 3, status: "deferred", mode: "refuse", mode_reason: "runner managers, controllers, tokens and router discovery describe physical CI machines and their credentials, not the org; GitLab restricts them to admins", mode_reviewed: "2026-09-01", tag: "Runners" }
      - { method: "GET", path: "/api/v4/runner_controllers/{runner_controller_id}/tokens/{id}", area: "runner controller tokens", tier: 3, status: "deferred", mode: "refuse", mode_reason: "runner managers, controllers, tokens and router discovery describe physical CI machines and their credentials, not the org; GitLab restricts them to admins", mode_reviewed: "2026-09-01", tag: "Runner controller tokens", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/runners", area: "runners", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon's jobs ran on nothing; needs a Runner the job table can point at", mode_reviewed: "2026-09-01", tag: "Runners" }
      - { method: "GET", path: "/api/v4/runners/{id}", area: "runners", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon's jobs ran on nothing; needs a Runner the job table can point at", mode_reviewed: "2026-09-01", tag: "Runners" }
      - { method: "GET", path: "/api/v4/runners/{id}/jobs", area: "runners", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon's jobs ran on nothing; needs a Runner the job table can point at", mode_reviewed: "2026-09-01", tag: "Runners" }
      - { method: "GET", path: "/api/v4/runners/{id}/managers", area: "runners", tier: 3, status: "deferred", mode: "refuse", mode_reason: "runner managers, controllers, tokens and router discovery describe physical CI machines and their credentials, not the org; GitLab restricts them to admins", mode_reviewed: "2026-09-01", tag: "Runners" }
      - { method: "GET", path: "/api/v4/runners/{id}/projects", area: "runners", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon's jobs ran on nothing; needs a Runner the job table can point at", mode_reviewed: "2026-09-01", tag: "Runners" }
      - { method: "GET", path: "/api/v4/runners/all", area: "runners", tier: 3, status: "deferred", mode: "refuse", mode_reason: "runner managers, controllers, tokens and router discovery describe physical CI machines and their credentials, not the org; GitLab restricts them to admins", mode_reviewed: "2026-09-01", tag: "Runners" }
      - { method: "GET", path: "/api/v4/runners/router/discovery", area: "runners", tier: 3, status: "deferred", mode: "refuse", mode_reason: "runner managers, controllers, tokens and router discovery describe physical CI machines and their credentials, not the org; GitLab restricts them to admins", mode_reviewed: "2026-09-01", tag: "CI runners" }
      - { method: "GET", path: "/api/v4/search", area: "search", tier: 2, status: "green", mode: "derive", tag: "Search" }
      - { method: "GET", path: "/api/v4/security/vulnerability_archive_exports/{id}", area: "vulnerabilities", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the export object can only be created by a POST we refuse, so the by-id read can only ever be the vendor's own 404", mode_reviewed: "2026-09-01", tag: "Vulnerabilities", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/security/vulnerability_archive_exports/{id}/download", area: "vulnerabilities", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the export object can only be created by a POST we refuse, so the by-id read can only ever be the vendor's own 404", mode_reviewed: "2026-09-01", tag: "Vulnerabilities", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/security/vulnerability_exports/{id}", area: "vulnerabilities", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the export object can only be created by a POST we refuse, so the by-id read can only ever be the vendor's own 404", mode_reviewed: "2026-09-01", tag: "Vulnerabilities", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/security/vulnerability_exports/{id}/download", area: "vulnerabilities", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the export object can only be created by a POST we refuse, so the by-id read can only ever be the vendor's own 404", mode_reviewed: "2026-09-01", tag: "Vulnerabilities", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/service_accounts", area: "service accounts", tier: 3, status: "green", mode: "empty", mode_reason: "every actor in olympus-labs is a person on the roster — canon mints no bot principal, and a service account served here would be a member no other host lists (invariant #5); GitLab answers `[]` at 200 for a group with none. THE LIST HALF, served as GitLab's empty page with the pagination headers the operation declares. UNGATED: canon has no `ServiceAccount` in any generation — hello-17 dropped the federation domain that would have introduced one, so every registered pin answers this same `[]`. Falsifiable: the `expectsEmpty` conformance entry reds the row the day canon grows one. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Service accounts", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/sidekiq/compound_metrics", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Sidekiq", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/sidekiq/job_stats", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Sidekiq", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/sidekiq/process_metrics", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Sidekiq", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/sidekiq/queue_metrics", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Sidekiq", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/snippet_repository_storage_moves", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Storage moves", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/snippet_repository_storage_moves/{repository_storage_move_id}", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Storage moves", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/snippets", area: "snippets", tier: 3, status: "green", mode: "empty", mode_reason: "no snippet exists in this organization — every shared file in olympus-labs lives in the parthenon repository and no persona has ever posted a snippet; GitLab answers `[]` at 200 for a snippet list and its own 404 for a snippet id that names nothing. THE LIST HALF, served as GitLab's empty page with the pagination headers the operation declares (`page`/`per_page`). UNGATED: canon has no `Snippet` entity in any generation — packages/canon/src/avatars-reactions.ts:188 names it as the blocker the hello-15 reaction domain could not answer — so every registered pin answers this same `[]`. Falsifiable: the `expectsEmpty` conformance entry reds the row the day canon grows a snippet. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Snippets" }
      - { method: "GET", path: "/api/v4/snippets/{id}", area: "snippets", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no snippet exists in this organization — every shared file in olympus-labs lives in the parthenon repository and no persona has ever posted a snippet; GitLab answers `[]` at 200 for a snippet list and its own 404 for a snippet id that names nothing. THE ID HALF: no snippet id resolves, so this operation never reaches a collection to be empty of and GitLab's own 404 is the whole answer — `[]` on a snippet's award-emoji or note list would assert that the snippet exists and holds nothing. UNGATED: canon has no `Snippet` in any generation, so the 404 is true on every artifact. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Snippets" }
      - { method: "GET", path: "/api/v4/snippets/{id}/files/{ref}/{file_path}/raw", area: "snippets", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no snippet exists in this organization — every shared file in olympus-labs lives in the parthenon repository and no persona has ever posted a snippet; GitLab answers `[]` at 200 for a snippet list and its own 404 for a snippet id that names nothing. THE ID HALF: no snippet id resolves, so this operation never reaches a collection to be empty of and GitLab's own 404 is the whole answer — `[]` on a snippet's award-emoji or note list would assert that the snippet exists and holds nothing. UNGATED: canon has no `Snippet` in any generation, so the 404 is true on every artifact. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Snippets" }
      - { method: "GET", path: "/api/v4/snippets/{id}/raw", area: "snippets", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no snippet exists in this organization — every shared file in olympus-labs lives in the parthenon repository and no persona has ever posted a snippet; GitLab answers `[]` at 200 for a snippet list and its own 404 for a snippet id that names nothing. THE ID HALF: no snippet id resolves, so this operation never reaches a collection to be empty of and GitLab's own 404 is the whole answer — `[]` on a snippet's award-emoji or note list would assert that the snippet exists and holds nothing. UNGATED: canon has no `Snippet` in any generation, so the 404 is true on every artifact. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Snippets" }
      - { method: "GET", path: "/api/v4/snippets/{id}/repository_storage_moves", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Storage moves", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/snippets/{id}/repository_storage_moves/{repository_storage_move_id}", area: "instance-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab answers 403 to a non-admin token here (Geo, Sidekiq, storage moves, LDAP, application settings, feature toggles, background migrations); a tenant-shaped mirror has no instance to administer", mode_reviewed: "2026-09-01", tag: "Storage moves", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/snippets/{id}/user_agent_detail", area: "snippets", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab exposes user-agent detail to instance administrators for abuse reports only; a non-admin token gets 403", mode_reviewed: "2026-09-01", tag: "Snippets" }
      - { method: "GET", path: "/api/v4/snippets/all", area: "snippets", tier: 3, status: "green", mode: "empty", mode_reason: "no snippet exists in this organization — every shared file in olympus-labs lives in the parthenon repository and no persona has ever posted a snippet; GitLab answers `[]` at 200 for a snippet list and its own 404 for a snippet id that names nothing. THE LIST HALF, served as GitLab's empty page with the pagination headers the operation declares (`page`/`per_page`). UNGATED: canon has no `Snippet` entity in any generation — packages/canon/src/avatars-reactions.ts:188 names it as the blocker the hello-15 reaction domain could not answer — so every registered pin answers this same `[]`. Falsifiable: the `expectsEmpty` conformance entry reds the row the day canon grows a snippet. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Snippets" }
      - { method: "GET", path: "/api/v4/snippets/public", area: "snippets", tier: 3, status: "green", mode: "empty", mode_reason: "no snippet exists in this organization — every shared file in olympus-labs lives in the parthenon repository and no persona has ever posted a snippet; GitLab answers `[]` at 200 for a snippet list and its own 404 for a snippet id that names nothing. THE LIST HALF, served as GitLab's empty page with the pagination headers the operation declares (`page`/`per_page`). UNGATED: canon has no `Snippet` entity in any generation — packages/canon/src/avatars-reactions.ts:188 names it as the blocker the hello-15 reaction domain could not answer — so every registered pin answers this same `[]`. Falsifiable: the `expectsEmpty` conformance entry reds the row the day canon grows a snippet. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Snippets" }
      - { method: "GET", path: "/api/v4/swagger_doc", area: "<none>", tier: 3, status: "deferred", mode: "derive", mode_reviewed: "2026-09-01", tag: "<none>", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/swagger_doc/{name}", area: "<none>", tier: 3, status: "deferred", mode: "derive", mode_reviewed: "2026-09-01", tag: "<none>", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/templates/dockerfiles", area: "templates", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no TemplateCatalog; GitLab's bundled Dockerfile/gitignore/CI/license templates are vendor content canon must carry", mode_reviewed: "2026-09-01", tag: "Templates", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/templates/dockerfiles/{name}", area: "templates", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no TemplateCatalog; GitLab's bundled Dockerfile/gitignore/CI/license templates are vendor content canon must carry", mode_reviewed: "2026-09-01", tag: "Templates", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/templates/gitignores", area: "templates", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W8) (hello-16 `refCatalogs`): reader.listGitignoreTemplates() over `license_catalog` (13 rows, bodies included) and `gitignore_template` (163 rows, source included) — the SAME two compile-time tables GitHub's /licenses and /gitignore/templates already serve, which is what makes a licence fetched through either host the same licence (invariant #5). GENERATION-GATED and `[]` is not an option: an artifact without the catalogs answers the template-catalog generation gap, because `[]` here would say GitLab bundles no licence templates — a claim about the HOST rather than about this organization, and a false one. licence: FACTUAL/CC0 — the licence texts are the licences themselves and the ignore-file templates are github/gitignore's CC0-1.0 corpus, the same grant coverage/reviews/2026-09-09-hello-15-stale-reasons-git-hosts.md records for the GitHub twins. `Entities::TemplatesList` is `{key, name}`, and an ignore-file template is its own key: GitLab derives both from the file name, which conformance asserts rather than assumes", mode_reviewed: "2026-09-12", tag: "Templates", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/templates/gitignores/{name}", area: "templates", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W8) (hello-16 `refCatalogs`): reader.gitignoreTemplate(name) over `license_catalog` (13 rows, bodies included) and `gitignore_template` (163 rows, source included) — the SAME two compile-time tables GitHub's /licenses and /gitignore/templates already serve, which is what makes a licence fetched through either host the same licence (invariant #5). GENERATION-GATED and `[]` is not an option: an artifact without the catalogs answers the template-catalog generation gap, because `[]` here would say GitLab bundles no licence templates — a claim about the HOST rather than about this organization, and a false one. licence: FACTUAL/CC0 — the licence texts are the licences themselves and the ignore-file templates are github/gitignore's CC0-1.0 corpus, the same grant coverage/reviews/2026-09-09-hello-15-stale-reasons-git-hosts.md records for the GitHub twins. CASE-SENSITIVE, as upstream's own file names are: `Node` resolves and `node` does not, which is what gitlab.com does and what GitHub's `/gitignore/templates/{name}` does on this same table", mode_reviewed: "2026-09-12", tag: "Templates", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/templates/gitlab_ci_ymls", area: "templates", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no TemplateCatalog; GitLab's bundled Dockerfile/gitignore/CI/license templates are vendor content canon must carry", mode_reviewed: "2026-09-01", tag: "Templates", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/templates/gitlab_ci_ymls/{name}", area: "templates", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no TemplateCatalog; GitLab's bundled Dockerfile/gitignore/CI/license templates are vendor content canon must carry", mode_reviewed: "2026-09-01", tag: "Templates", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/templates/licenses", area: "templates", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W8) (hello-16 `refCatalogs`): reader.listLicenses() over `license_catalog` (13 rows, bodies included) and `gitignore_template` (163 rows, source included) — the SAME two compile-time tables GitHub's /licenses and /gitignore/templates already serve, which is what makes a licence fetched through either host the same licence (invariant #5). GENERATION-GATED and `[]` is not an option: an artifact without the catalogs answers the template-catalog generation gap, because `[]` here would say GitLab bundles no licence templates — a claim about the HOST rather than about this organization, and a false one. licence: FACTUAL/CC0 — the licence texts are the licences themselves and the ignore-file templates are github/gitignore's CC0-1.0 corpus, the same grant coverage/reviews/2026-09-09-hello-15-stale-reasons-git-hosts.md records for the GitHub twins. `popular` IS the catalog's own `featured` flag rather than a second judgement, and `?popular=true` narrows on it. `content` is the stored body VERBATIM — upstream's `[fullname]` placeholder included — because only the single-template operation declares the parameters that expand it. `nickname`, `html_url` and `source_url` are OMITTED: canon's licence row deliberately stores no URL and no nickname (a URL is a host's rendering of the row, not a fact about the licence), GitLab points both URLs at choosealicense.com, which is a link out of the sandbox, and this host publishes no licence page to point at instead", mode_reviewed: "2026-09-12", tag: "Templates", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/templates/licenses/{name}", area: "templates", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W8) (hello-16 `refCatalogs`): reader.license(key) over `license_catalog` (13 rows, bodies included) and `gitignore_template` (163 rows, source included) — the SAME two compile-time tables GitHub's /licenses and /gitignore/templates already serve, which is what makes a licence fetched through either host the same licence (invariant #5). GENERATION-GATED and `[]` is not an option: an artifact without the catalogs answers the template-catalog generation gap, because `[]` here would say GitLab bundles no licence templates — a claim about the HOST rather than about this organization, and a false one. licence: FACTUAL/CC0 — the licence texts are the licences themselves and the ignore-file templates are github/gitignore's CC0-1.0 corpus, the same grant coverage/reviews/2026-09-09-hello-15-stale-reasons-git-hosts.md records for the GitHub twins. `{name}` is the licence KEY the collection's own `key` field hands a caller, and a key outside the thirteen is GitLab's own 404 rather than a coverage miss — the catalog resolves, this key is simply not in it. The two documented parameters are HONOURED rather than ignored: `project` and `fullname` substitute upstream's `[project]` and `[fullname]` the way LicenseTemplate#resolve! does. `[year]` is deliberately NOT substituted — real GitLab fills it from the wall clock, and a replica whose answer changed with the calendar would stop being byte-reproducible across the pins", mode_reviewed: "2026-09-12", tag: "Templates", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/todos", area: "todos", tier: 2, status: "green", mode: "empty", mode_reason: "the calling persona has no pending to-do — canon carries no per-person work queue and every review request it would echo is already served at /merge_requests; GitLab answers `[]` at 200 for a caller with an empty queue. THE LIST HALF, served as GitLab's empty page with the pagination headers the operation declares. UNGATED: canon carries no per-person work queue in any generation, so every registered pin answers this same `[]`. Falsifiable: the `expectsEmpty` conformance entry reds the row the day canon grows one. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "To-dos" }
      - { method: "GET", path: "/api/v4/topics", area: "project topics", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W3): the distinct topics across this instance's projects with the number of projects carrying each, read from repo.topics_json. THE OLD REASON - canon's repo carries no topics - WAS FALSE: the column is real, shapeProject has published it as `topics`/`tag_list` on every project object since wave A, and ?topic= already filters the project list by it. Sorted by project count descending, which is GitLab's own order, tie-broken by name so one artifact always paginates one way. `title`, `description`, `avatar_url` and `organization_id` are omitted: a GitLab topic is an object an administrator creates and titles, canon carries the SLUG and nothing else, and title-casing the slug would be a string this universe never wrote. `search` narrows and is asserted to; `without_projects=true` is empty because every topic here IS a project's own tag; `organization_id` is an explicit error because this universe models no GitLab organization", mode_reviewed: "2026-09-12", tag: "Project topics", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/topics/{id}", area: "project topics", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W3): the by-id twin of /api/v4/topics, addressed by the id minted from the topic's own name - two projects tagged `platform` are tagged the same topic. Conformance asserts the list and the by-id row render one topic the same way and that an unknown id is GitLab's 404. Same falsified reason as the list", mode_reviewed: "2026-09-12", tag: "Project topics", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/usage_data/metric_definitions", area: "metrics", tier: 3, status: "deferred", mode: "refuse", mode_reason: "service ping reports what a real installation sends to GitLab Inc.; a mirror has no installation to report on and the endpoints are admin-only", mode_reviewed: "2026-09-01", tag: "Metrics", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/usage_data/non_sql_metrics", area: "usage data", tier: 3, status: "deferred", mode: "refuse", mode_reason: "service ping reports what a real installation sends to GitLab Inc.; a mirror has no installation to report on and the endpoints are admin-only", mode_reviewed: "2026-09-01", tag: "Usage data", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/usage_data/queries", area: "usage data", tier: 3, status: "deferred", mode: "refuse", mode_reason: "service ping reports what a real installation sends to GitLab Inc.; a mirror has no installation to report on and the endpoints are admin-only", mode_reviewed: "2026-09-01", tag: "Usage data", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/usage_data/service_ping", area: "usage data", tier: 3, status: "deferred", mode: "refuse", mode_reason: "service ping reports what a real installation sends to GitLab Inc.; a mirror has no installation to report on and the endpoints are admin-only", mode_reviewed: "2026-09-01", tag: "Usage data", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/user", area: "users", tier: 1, status: "green", mode: "derive", tag: "Users" }
      - { method: "GET", path: "/api/v4/user_counts", area: "users", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Users" }
      - { method: "GET", path: "/api/v4/user/activities", area: "users", tier: 1, status: "planned", mode: "refuse", mode_reason: "GitLab restricts the instance-wide last-activity index to administrators", mode_reviewed: "2026-09-01", tag: "Users" }
      - { method: "GET", path: "/api/v4/user/applications", area: "applications", tier: 3, status: "deferred", mode: "refuse", mode_reason: "application registration is a control-plane surface of the vendor's auth system; SandboxAPIs issues its own keys and the instance list is admin-only", mode_reviewed: "2026-09-01", tag: "Applications", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/user/applications/{id}", area: "applications", tier: 3, status: "deferred", mode: "refuse", mode_reason: "application registration is a control-plane surface of the vendor's auth system; SandboxAPIs issues its own keys and the instance list is admin-only", mode_reviewed: "2026-09-01", tag: "Applications", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/user/emails", area: "users", tier: 1, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W3): reader.credentialsForPerson(athena, 'email') - athena is the caller GET /api/v4/user reports, and GitHub's /user/emails has been green off the same person_credential rows since the hello-16 credential wave. `confirmed_at` is the credential's own instant and is sent only on an ACTIVE row: GitLab's field records when the address was confirmed to belong to its owner, canon records when the person came to hold it, and a row canon ever revokes loses the field in the same edit rather than keeping a confirmation that is no longer true. `id` is the integer real GitLab sends where the vendored component types it string, so the row is a deviation. Behind the hello-16 credential gate, not the hello-17 caller gate: the caller has held an address since hello-16, which is a different question from whether she holds a key. The old reason - canon's person carries no email list - was falsified by that generation", mode_reviewed: "2026-09-12", tag: "Users" }
      - { method: "GET", path: "/api/v4/user/emails/{email_id}", area: "users", tier: 1, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W3): the by-id twin of /api/v4/user/emails, addressed by gitlabId(credential.id); conformance asserts the list and the by-id row render one address the same way. Same hello-16 gate, same `id` deviation, same falsified reason", mode_reviewed: "2026-09-12", tag: "Users" }
      - { method: "GET", path: "/api/v4/user/gpg_keys", area: "deploy-keys-tokens", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): the caller's OpenPGP keys, from the founding member's four kinds. The armored `key` block stays omitted rather than invented: a transferable key needs a self-signature made with a private half this universe never generates, and an armored block that failed to import would be a placeholder in a convincing costume (the hello-16 GPG ruling, unchanged). Answers the named hello-17 generation gap on every older artifact", mode_reviewed: "2026-09-12", tag: "Keys" }
      - { method: "GET", path: "/api/v4/user/gpg_keys/{key_id}", area: "deploy-keys-tokens", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): the by-id twin of the caller's GPG key list, resolving exactly what that list carries", mode_reviewed: "2026-09-12", tag: "Keys" }
      - { method: "GET", path: "/api/v4/user/keys", area: "deploy-keys-tokens", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): features.callerCredentials makes the FOUNDING MEMBER hold one of every credential kind this organization accepts, and defines the caller as the founding member - so the persona GET /user reports now holds an ssh-auth key, a signing key, a GPG key and an ACTIVE personal token. This route serves both SSH kinds off credentialsForPerson told apart by usage_type, and the rows are byte-identical to /users/{id}/keys for the same person (one canonical person rendered once). On hello-16 and all 127 registered pins it answers the named hello-17 generation gap and never [], because an empty caller key list reports a fact about WHO THE CALLER IS rather than about this organization", mode_reviewed: "2026-09-12", tag: "Keys" }
      - { method: "GET", path: "/api/v4/user/keys/{key_id}", area: "deploy-keys-tokens", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): the by-id twin of the caller's SSH key list, resolving exactly what that list carries so the two cannot disagree about what this caller holds. Blocked until now by the same fact - the caller held no key, so no id could ever return 200 - and unblocked by the same one", mode_reviewed: "2026-09-12", tag: "Keys" }
      - { method: "GET", path: "/api/v4/user/preferences", area: "users", tier: 1, status: "planned", mode: "generate", mode_reason: "canon's person carries no email list, preferences or status message", mode_reviewed: "2026-09-01", tag: "Users" }
      - { method: "GET", path: "/api/v4/user/status", area: "users", tier: 1, status: "deviation", mode: "empty", mode_reason: "nobody in olympus-labs sets a status message — canon's person carries no availability, emoji or status text; GitLab's own answer for a user who has set none is a 200 with every field null. NOT A COLLECTION: `APIEntitiesUserStatus` is an object, so the honest empty is the all-null object rather than `[]`. All five fields are a `deviation` against the vendored component, which types each of them `string` with no `nullable` while GitLab renders `Entities::UserStatus` over a person who has set no status and every field comes out nil. UNGATED: `canon.Person` (packages/canon/src/entities.ts:79) has carried id, archetype, teams, utcOffsetMinutes, isBot and member in every generation and has grown only `aiTool`/`extraAiTools` since, so no artifact of this universe has ever held an availability, an emoji or a status text. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Users" }
      - { method: "GET", path: "/api/v4/user/support_pin", area: "users", tier: 1, status: "planned", mode: "refuse", mode_reason: "a support PIN authenticates a human to GitLab Support; SandboxAPIs has no support desk and issuing one would be a credential-shaped lie", mode_reviewed: "2026-09-01", tag: "Users" }
      - { method: "GET", path: "/api/v4/users", area: "users", tier: 1, status: "green", mode: "derive", tag: "Users" }
      - { method: "GET", path: "/api/v4/users/{id}", area: "users", tier: 1, status: "green", mode: "derive", tag: "Users" }
      - { method: "GET", path: "/api/v4/users/{id}/associations_count", area: "users", tier: 1, status: "deviation", mode: "derive", mode_reviewed: "2026-09-01", tag: "Users" }
      - { method: "GET", path: "/api/v4/users/{id}/custom_attributes", area: "custom attributes", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab restricts custom attributes to instance administrators; a non-admin token gets 403", mode_reviewed: "2026-09-01", tag: "Custom attributes", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/users/{id}/custom_attributes/{key}", area: "custom attributes", tier: 3, status: "deferred", mode: "refuse", mode_reason: "GitLab restricts custom attributes to instance administrators; a non-admin token gets 403", mode_reviewed: "2026-09-01", tag: "Custom attributes", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/users/{id}/emails", area: "users", tier: 1, status: "planned", mode: "refuse", mode_reason: "GitLab restricts another user's addresses to instance administrators and this host authenticates as an ordinary member of one group, so GitLab's own 403 is the whole answer. THE OLD REASON WAS FALSIFIED RATHER THAN UPHELD: it said canon's person carries no email list, and hello-16 gave it one — person_credential kind `email`, which /api/v4/user/emails serves today — so the blocker is the TOKEN, not the canon, which is the same reading that puts the whole /api/v4/admin/* family in class 1 of the 2026-09-01 wave. /api/v4/user/emails is deliberately untouched and still served: a caller reading their OWN addresses needs no administrator, and that distinction is what this row turns on. UNGATED: no generation of this universe authenticates as an instance administrator. RULED by the founder 2026-09-12 (round 20)", mode_reviewed: "2026-09-12", tag: "Users" }
      - { method: "GET", path: "/api/v4/users/{id}/events", area: "events", tier: 2, status: "green", mode: "derive", tag: "Events" }
      - { method: "GET", path: "/api/v4/users/{id}/followers", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): features.socialGraph derives the follow edges from the review graph - you follow the people whose changes you review most and the people who review yours - in ONE person_follow table both git hosts read, which is the cross-host parity this reason has committed to since the classification run. Ordered by the follower's canonical id, the order both hosts page. On every older artifact it answers the named hello-17 generation gap, because [] would assert that nobody here follows anybody", mode_reviewed: "2026-09-12", tag: "Users" }
      - { method: "GET", path: "/api/v4/users/{id}/following", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): the other end of the same directed edge, off the same person_follow table, ordered by the followee's canonical id. Every edge a person's /followers names is visible from that follower's /following, and no edge names the same person twice", mode_reviewed: "2026-09-12", tag: "Users" }
      - { method: "GET", path: "/api/v4/users/{id}/gpg_keys", area: "deploy-keys-tokens", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-10 (hello-16): reader.credentialsForPerson(person, \"gpg\") (reader.ts:3075). THE ARMORED `key` FIELD IS OMITTED AND THAT IS THE HONEST ANSWER: `APIEntitiesGpgKey` has three properties and `key` is the ARMORED TRANSFERABLE key, which is a public-key packet PLUS a user id PLUS a self-signature binding them — and a self-signature needs a private half this universe never generated (decisions/2026-09-09-1347). An armored block emitted here would fail `gpg --import`: a placeholder that LOOKS importable. The component declares no `required` list, so a response without `key` is a legal one; `null` would additionally violate its declared `type: string`. GitHub's shape has somewhere honest to put the material (a required `public_key` beside a nullable `raw_key`) and GitLab's does not. `id` and `created_at` are the row's own", mode_reviewed: "2026-09-10", tag: "Keys" }
      - { method: "GET", path: "/api/v4/users/{id}/gpg_keys/{key_id}", area: "deploy-keys-tokens", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-10 (hello-16): the same rows by id, byte-identical to the list's first entry (conformance asserts it). The armored-key omission is the list row's ruling and applies here unchanged", mode_reviewed: "2026-09-10", tag: "Keys" }
      - { method: "GET", path: "/api/v4/users/{id}/keys/{key_id}", area: "deploy-keys-tokens", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-10 (hello-16): the same rows addressed by gitlabId(PersonCredentialRow.id) — conformance asserts the by-id form is byte-identical to the list's own first row, so the two cannot describe one key two ways. An id the person does not hold is GitLab's own 404 Key Not Found", mode_reviewed: "2026-09-10", tag: "Keys" }
      - { method: "GET", path: "/api/v4/users/{id}/support_pin", area: "users", tier: 1, status: "planned", mode: "refuse", mode_reason: "a support PIN authenticates a human to GitLab Support; SandboxAPIs has no support desk and issuing one would be a credential-shaped lie", mode_reviewed: "2026-09-01", tag: "Users" }
      - { method: "GET", path: "/api/v4/users/{user_id}/contributed_projects", area: "projects", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "Projects" }
      - { method: "GET", path: "/api/v4/users/{user_id}/impersonation_tokens", area: "deploy-keys-tokens", tier: 3, status: "deferred", mode: "refuse", mode_reason: "listing every key, deploy token or impersonation token across the instance requires admin on GitLab; answering would be inventing an admin session", mode_reviewed: "2026-09-01", tag: "Access tokens" }
      - { method: "GET", path: "/api/v4/users/{user_id}/impersonation_tokens/{impersonation_token_id}", area: "deploy-keys-tokens", tier: 3, status: "deferred", mode: "refuse", mode_reason: "listing every key, deploy token or impersonation token across the instance requires admin on GitLab; answering would be inventing an admin session", mode_reviewed: "2026-09-01", tag: "Access tokens" }
      - { method: "GET", path: "/api/v4/users/{user_id}/keys", area: "deploy-keys-tokens", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-10 (hello-16): reader.credentialsForPerson(person, \"ssh-auth\") + (\"ssh-signing\") (packages/artifact/src/reader.ts:3075). ONE LIST FOR BOTH GRANTS, which is GitLab's shape rather than GitHub's: an authentication key and a signing key are told apart by `usage_type` (auth/signing) instead of by two endpoints, so canon's two kinds survive the crossing. `key` is the artifact's own OpenSSH line and re-hashes to its `fingerprint_sha256` under ssh-keygen -lf, which conformance recomputes; `expires_at` and `last_used_at` are omitted when canon carries none (the vendored component declares no required list and types both non-nullable, the deploy-key precedent). Gated on reader.hasCredentials(): every pre-hello-16 pin answers the noCredentials generation-gap 404 rather than [], because an empty key list asserts that this person pushes with nothing", mode_reviewed: "2026-09-10", tag: "Keys" }
      - { method: "GET", path: "/api/v4/users/{user_id}/memberships", area: "users", tier: 1, status: "deviation", mode: "derive", mode_reviewed: "2026-09-01", tag: "Users" }
      - { method: "GET", path: "/api/v4/users/{user_id}/project_deploy_keys", area: "deploy-keys-tokens", tier: 3, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W8) (hello-15 `ciConfig`): canon.CheckoutKey IS a deploy key — `CheckoutKeyType` is literally \"deploy-key\" — and reader.listCheckoutKeys(repo) already carries the OpenSSH line and BOTH fingerprints in the forms GitLab prints them. `title` is the comment at the end of that same line, READ OFF the material rather than kept as a second copy, so the title and the key can never name two different things; `created_at` is created_epoch; `fingerprint` is the colon-hex MD5 and `fingerprint_sha256` the OpenSSH form. `expires_at`, `last_used_at` and `usage_type` are OMITTED rather than nulled: this universe issues no key with an expiry, records no use of one and stores no usage flag, all three are optional, and a null typed `string` would buy a deviation for nothing. GENERATION-GATED: an artifact without the CI-configuration domain answers that gap rather than `[]`, because `[]` would say this project's CI clones with nothing. `Entities::DeployKey` RATHER THAN `DeployKeysProject`, which is why this row alone publishes the two project arrays and carries no `can_push`: the whole point of a user-scoped key list is saying WHICH projects each key reaches. `projects_with_write_access` is EMPTY and the project sits under `projects_with_readonly_access`, because `can_push` is false on these keys — listing the project as a write grant while the project-scoped row says the key cannot push would be this host contradicting itself about one key (invariant #5). Both arrays are a `deviation`, the vendored component typing each as a single object while real GitLab sends a collection. The PERSON still has to resolve, so an id nobody holds is GitLab's own 404 rather than a list about nobody", mode_reviewed: "2026-09-12", tag: "Deploy resources" }
      - { method: "GET", path: "/api/v4/users/{user_id}/projects", area: "projects", tier: 1, status: "green", mode: "empty", mode_reason: "the projects a person owns in their OWN namespace. Canon models no personal namespace — the group owns every project — so nobody owns one. users/{id}/contributed_projects answers the question this is often mistaken for, and it is served with real rows. RULED by the founder 2026-09-09; a subgroup and group-level objects are on hello-16", mode_reviewed: "2026-09-09", tag: "Projects" }
      - { method: "GET", path: "/api/v4/users/{user_id}/starred_projects", area: "projects", tier: 1, status: "planned", mode: "generate", mode_reason: "canon has no Star; the founder ruled stars generated on both hosts so a starred repo is the same repo on GitHub and GitLab", mode_reviewed: "2026-09-01", tag: "Projects" }
      - { method: "GET", path: "/api/v4/users/{user_id}/status", area: "users", tier: 1, status: "deviation", mode: "empty", mode_reason: "nobody in olympus-labs sets a status message — canon's person carries no availability, emoji or status text; GitLab's own answer for a user who has set none is a 200 with every field null. NOT A COLLECTION: `APIEntitiesUserStatus` is an object, so the honest empty is the all-null object rather than `[]`. All five fields are a `deviation` against the vendored component, which types each of them `string` with no `nullable` while GitLab renders `Entities::UserStatus` over a person who has set no status and every field comes out nil. UNGATED: `canon.Person` (packages/canon/src/entities.ts:79) has carried id, archetype, teams, utcOffsetMinutes, isBot and member in every generation and has grown only `aiTool`/`extraAiTools` since, so no artifact of this universe has ever held an availability, an emoji or a status text. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "Users" }
      - { method: "GET", path: "/api/v4/version", area: "instance-admin", tier: 3, status: "green", mode: "derive", tag: "Metadata", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/vscode/settings_sync/{settings_context_hash}/v1/manifest", area: "vscode", tier: 3, status: "deferred", mode: "refuse", mode_reason: "this is per-caller editor storage, not a record of the org; it 404s until the caller WRITES settings, and writes are refused", mode_reviewed: "2026-09-01", tag: "VSCode", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/vscode/settings_sync/{settings_context_hash}/v1/resource/{resource_name}", area: "vscode", tier: 3, status: "deferred", mode: "refuse", mode_reason: "this is per-caller editor storage, not a record of the org; it 404s until the caller WRITES settings, and writes are refused", mode_reviewed: "2026-09-01", tag: "VSCode", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/vscode/settings_sync/{settings_context_hash}/v1/resource/{resource_name}/{id}", area: "vscode", tier: 3, status: "deferred", mode: "refuse", mode_reason: "this is per-caller editor storage, not a record of the org; it 404s until the caller WRITES settings, and writes are refused", mode_reviewed: "2026-09-01", tag: "VSCode", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/vscode/settings_sync/v1/manifest", area: "vscode", tier: 3, status: "deferred", mode: "refuse", mode_reason: "this is per-caller editor storage, not a record of the org; it 404s until the caller WRITES settings, and writes are refused", mode_reviewed: "2026-09-01", tag: "VSCode", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/vscode/settings_sync/v1/resource/{resource_name}", area: "vscode", tier: 3, status: "deferred", mode: "refuse", mode_reason: "this is per-caller editor storage, not a record of the org; it 404s until the caller WRITES settings, and writes are refused", mode_reviewed: "2026-09-01", tag: "VSCode", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/vscode/settings_sync/v1/resource/{resource_name}/{id}", area: "vscode", tier: 3, status: "deferred", mode: "refuse", mode_reason: "this is per-caller editor storage, not a record of the org; it 404s until the caller WRITES settings, and writes are refused", mode_reviewed: "2026-09-01", tag: "VSCode", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/vulnerabilities/{id}", area: "vulnerabilities", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no SecurityFinding/SbomComponent/Attestation; a scanning org has findings", mode_reviewed: "2026-09-01", tag: "Vulnerabilities", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/vulnerabilities/{id}/issue_links", area: "vulnerabilities", tier: 3, status: "deferred", mode: "generate", mode_reason: "canon has no SecurityFinding/SbomComponent/Attestation; a scanning org has findings", mode_reviewed: "2026-09-01", tag: "Vulnerabilities", flag: "needs-tier-review" }
      - { method: "GET", path: "/api/v4/web_commits/public_key", area: "web commits", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no commit or tag in this universe is GPG-signed, and GitLab answers its own 404 'GPG Signature Not Found' for an unsigned object", mode_reviewed: "2026-09-01", tag: "Web commits", flag: "needs-tier-review" }
    graphql:
      - { entity: "branches-tags", type: "Tree", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W3): Project.repository's rootRef, branchCount, tagCount and branchNames(searchPattern,offset,limit) - which is the WHOLE of GitLab's branch surface in GraphQL: its schema publishes no branch object, and mirroring that rather than inventing a richer type is invariant #2. Tags are reached the way GitLab reaches them, through Release. The counters are asserted equal to what `/repository/branches` and `/repository/tags` list", mode_reviewed: "2026-09-12", graphql_only: false }
      - { entity: "commits", type: "Commit", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W3): Project.repository.commit(ref) and commits(ref, first, after). Every field is shapeCommit's own value for the same row, so a client cannot read one sha, title or date here and another from `/repository/commits`; the connection walks the SAME ancestry `/repository/commits?ref_name=` walks rather than every commit in the table. `description` is the message below the title and null for a one-liner, which is GitLab's own reading", mode_reviewed: "2026-09-12", graphql_only: false }
      - { entity: "groups", type: "Group", root_field: "group", tier: 1, status: "green", mode: "derive", graphql_only: false }
      - { entity: "issues", type: "Issue", tier: 1, status: "green", mode: "derive", graphql_only: false }
      - { entity: "labels", type: "Label", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W3): Project.label(title) and labels(first, after, title). REST's `name` is GraphQL's `title` and the colours are glLabel's own two strings; `createdAt`/`updatedAt` are OMITTED rather than derived, because canon's label row carries no instant at all and GitLab types both non-null - a subset may omit a field, and inventing a creation date for a label would be a placeholder", mode_reviewed: "2026-09-12", graphql_only: false }
      - { entity: "merge-requests", type: "MergeRequest", tier: 1, status: "green", mode: "derive", graphql_only: false }
      - { entity: "milestones", type: "Milestone", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W3): Project.milestones(first, after, state, title), every field glMilestone's own value for the same row - including the two dates ArtifactReader.milestoneTimes derives, so GraphQL and `/milestones` cannot print different ones. `projectMilestone` is true and the two group flags false because canon's `milestone.repo` is never null", mode_reviewed: "2026-09-12", graphql_only: false }
      - { entity: "projects", type: "Project", root_field: "project", tier: 1, status: "green", mode: "derive", graphql_only: false }
      - { entity: "releases", type: "Release", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W3): Project.release(tagName) and releases(first, after), every field glRelease's own value for the same row, with `commit` resolving to the same Commit type the repository serves so a release's tag commit is fetchable from either dialect", mode_reviewed: "2026-09-12", graphql_only: false }
      - { entity: "repository-files", type: "Blob", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W3): Repository.tree(path, recursive, ref) with its Blob and TreeEntry connections, and Repository.blobs(paths, ref) for the CONTENT - the GraphQL twin of `/repository/files/{path}`, asserted byte-equal to it. `flatPath` is computed from the artifact's own trees by git's real rule (a directory whose sub-tree holds exactly one directory collapses into it) rather than copied from `path`. `size`/`rawSize` are omitted: they are GitLab's BigInt scalar, which serialises as a string, and a subset promising Int would hand clients the wrong JSON type. Answers the named hello-4 file generation gap on an artifact without the file model", mode_reviewed: "2026-09-12", graphql_only: false }
      - { entity: "users", type: "UserCore", root_field: "user", tier: 1, status: "green", mode: "derive", graphql_only: false }
      - { entity: "work-items", type: "WorkItem", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W3): GitLab's unified issue/epic type: Project.workItems is the project's ISSUES and Group.workItems the group's EPICS, which is what the two roots mean. Every issue field is glIssue's own value including the `closed_epoch ?? created_epoch` derivation of updatedAt, and `confidential: false` is knowable rather than a default - canon models no private issue or epic. On an artifact predating hello-16 the GROUP half answers an explicit generation error in `errors` rather than an empty connection, which would assert that this organization plans nothing (invariant #4's GraphQL clause)", mode_reviewed: "2026-09-12", graphql_only: true }
    git: [] # git smart-HTTP is not served for this provider yet (SPEC rev 9: GitHub first)
  bitbucket:
    rest:
      - { method: "GET", path: "/addon/{addon_key}/client-key", area: "addon", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no Atlassian Connect app is installed on this workspace; these routes are addressed to an installed app's own key scope and Bitbucket answers 404 to a caller that is not that app (the ruled Jira Connect/Forge precedent, coverage/reviews/2026-09-01-jira-modes.md row 1)", mode_reviewed: "2026-09-01", tag: "Addon" }
      - { method: "GET", path: "/hook_events", area: "webhooks-config", tier: 3, status: "deferred", mode: "derive", mode_reviewed: "2026-09-01", tag: "Webhooks" }
      - { method: "GET", path: "/hook_events/{subject_type}", area: "webhooks-config", tier: 3, status: "deferred", mode: "derive", mode_reviewed: "2026-09-01", tag: "Webhooks" }
      - { method: "GET", path: "/repositories", area: "repos", tier: 1, status: "green", mode: "derive", tag: "Repositories" }
      - { method: "GET", path: "/repositories/{workspace}", area: "repos", tier: 1, status: "green", mode: "derive", tag: "Repositories" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}", area: "repos", tier: 1, status: "green", mode: "derive", tag: "Repositories" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/branch-restrictions", area: "branch-restrictions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity BranchRestriction", mode_reviewed: "2026-09-01", tag: "Branch restrictions" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/branch-restrictions/{id}", area: "branch-restrictions", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity BranchRestriction", mode_reviewed: "2026-09-01", tag: "Branch restrictions" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/branching-model", area: "branching-model", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity BranchingModel", mode_reviewed: "2026-09-01", tag: "Branching model" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/branching-model/settings", area: "branching-model", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity BranchingModel", mode_reviewed: "2026-09-01", tag: "Branching model" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/commit/{commit}", area: "commits", tier: 1, status: "green", mode: "derive", tag: "Commits" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/commit/{commit}/comments", area: "commits", tier: 1, status: "green", mode: "empty", mode_reason: "the same fact as the GitHub row, on the third git host: canon carries no commit comments. The commit is resolved first, so a bad SHA still 404s and a client can tell 'no comments' from 'no such commit' (DECISIONS 2026-08-20 [commit-detail] decision 2)", mode_reviewed: "2026-08-20", tag: "Commits" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/commit/{commit}/comments/{comment_id}", area: "commits", tier: 1, status: "planned", mode: "refuse", mode_reason: "the id half of an empty this file already ruled and a test already arms: canon carries no commit comments (DECISIONS 2026-08-20 [commit-detail] decision 2, the `mode: empty` row directly above this one), so no comment id can resolve and Bitbucket's own 404 is the only possible answer", mode_reviewed: "2026-09-01", tag: "Commits" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/commit/{commit}/properties/{app_key}/{property_name}", area: "addon-properties", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no Atlassian Connect app is installed on this workspace; these routes are addressed to an installed app's own key scope and Bitbucket answers 404 to a caller that is not that app (the ruled Jira Connect/Forge precedent, coverage/reviews/2026-09-01-jira-modes.md row 1)", mode_reviewed: "2026-09-01", tag: "properties" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/commit/{commit}/pullrequests", area: "pulls", tier: 1, status: "green", mode: "derive", tag: "Pullrequests" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/commit/{commit}/reports", area: "code-insights", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityFinding", mode_reviewed: "2026-09-01", tag: "Reports" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/commit/{commit}/reports/{reportId}", area: "code-insights", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityFinding", mode_reviewed: "2026-09-01", tag: "Reports" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/commit/{commit}/reports/{reportId}/annotations", area: "code-insights", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityFinding", mode_reviewed: "2026-09-01", tag: "Reports" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/commit/{commit}/reports/{reportId}/annotations/{annotationId}", area: "code-insights", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityFinding", mode_reviewed: "2026-09-01", tag: "Reports" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/commit/{commit}/statuses", area: "commit-statuses", tier: 1, status: "green", mode: "derive", tag: "Commit statuses" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/commit/{commit}/statuses/build/{key}", area: "commit-statuses", tier: 1, status: "green", mode: "derive", tag: "Commit statuses" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/commits", area: "commits", tier: 1, status: "green", mode: "derive", tag: "Commits" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/commits/{revision}", area: "commits", tier: 1, status: "green", mode: "derive", tag: "Commits" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/components", area: "issues-legacy", tier: 3, status: "excluded", mode: "unclassified", tag: "Issue tracker" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/components/{component_id}", area: "issues-legacy", tier: 3, status: "excluded", mode: "unclassified", tag: "Issue tracker" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/default-reviewers", area: "pulls", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): the approval rule's approvers, validated against `paginated_accounts`. hello-17 `reviewPolicy` (decisions/2026-09-11-0200) writes one approval rule per repository that has both merged pulls and an approver, and every field of it is a measurement: the approvers are the people with an `approve` review there, which is the same derivation the access pass uses to promote a plain member to repository `maintainer`, so the artifact holds ONE answer to \"who may approve here\" rather than two that can drift. Bitbucket's default reviewers are that rule read from the other end. THE ORDER IS THE RULE'S OWN — approvers is a comma-joined id list in canonical id order — and is deliberately NOT re-sorted by login, which would make the page order a function of the theme. Conformance re-derives the approver set from the review log and asserts every default reviewer really approved something in this repository. An artifact that predates the domain answers the hello-17 generation gap: an empty default-reviewer list would say this repository automatically requests nobody, which is a claim about how this team reviews rather than about the snapshot the caller pinned.", mode_reviewed: "2026-09-12", tag: "Pullrequests" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/default-reviewers/{target_username}", area: "pulls", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): one default reviewer, addressed by the account UUID, the Atlassian account id or the nickname — the three spellings this host resolves users by, and the nickname because the parameter is literally named for a username and a client that read one off the list will send it. Somebody who is not on the rule is Bitbucket's own 404, which conformance drives. An artifact that predates the domain answers the hello-17 generation gap: an empty default-reviewer list would say this repository automatically requests nobody, which is a claim about how this team reviews rather than about the snapshot the caller pinned.", mode_reviewed: "2026-09-12", tag: "Pullrequests" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/deploy-keys", area: "deployments", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09: reader.listCheckoutKeys(repo) (packages/artifact/src/reader.ts:2351). canon.CheckoutKeyType is literally \"deploy-key\" (packages/canon/src/ci-config.ts:221); the served `key` and `comment` reassemble CheckoutKeyRow.public_key exactly, and the conformance entry base64-decodes the blob and SHA-256s it back to the artifact's own fingerprint_sha256 — which is what separates a key from a string shaped like one. `last_used` is omitted because canon records no use of any key", mode_reviewed: "2026-09-09", tag: "Deployments" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/deploy-keys/{key_id}", area: "deployments", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09: reader.listCheckoutKeys(repo) (packages/artifact/src/reader.ts:2351). canon.CheckoutKeyType is literally \"deploy-key\" (packages/canon/src/ci-config.ts:221); the served `key` and `comment` reassemble CheckoutKeyRow.public_key exactly, and the conformance entry base64-decodes the blob and SHA-256s it back to the artifact's own fingerprint_sha256 — which is what separates a key from a string shaped like one. `last_used` is omitted because canon records no use of any key. Addressed by the numeric key_id the spec's own examples use, derived through bbInt like every other numeric Bitbucket id", mode_reviewed: "2026-09-09", tag: "Deployments" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/deployments", area: "deployments", tier: 2, status: "green", mode: "derive", tag: "Deployments" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/deployments_config/environments/{environment_uuid}/variables", area: "pipelines", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` - the same canon GitHub serves as Actions secrets and variables, in Bitbucket's dialect. `secured` IS canon's `masked`, so the two hosts cannot disagree about which of this organization's settings may be published, and `value` is `\"\"` on a secured row because the vendored property description says so in as many words (\"If the variable is secured, this will be empty\") - canon holds NO value for a masked binding, so the empty string is composed at the boundary from the absence. `deployment_variable` at a deployment ENVIRONMENT, resolved through the same `envUuid` `/environments` publishes - so a uuid read off that list is one this row answers for", mode_reviewed: "2026-09-12", tag: "Pipelines" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/deployments/{deployment_uuid}", area: "deployments", tier: 2, status: "green", mode: "derive", tag: "Deployments" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/diff/{spec}", area: "commits", tier: 1, status: "green", mode: "derive", tag: "Commits" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/diffstat/{spec}", area: "commits", tier: 1, status: "green", mode: "derive", tag: "Commits" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/downloads", area: "downloads", tier: 3, status: "green", mode: "derive", mode_reason: "hello-13's Download canon: the newest release publishes a tarball and a .sha256sums, so the download area lists real files with real sizes and download counts", mode_reviewed: "2026-09-02", tag: "Downloads" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/downloads/{filename}", area: "downloads", tier: 3, status: "green", mode: "derive", mode_reason: "the operation the document titles Get a download artifact link, whose only documented answer is a 302; we redirect to the same links.download href the list publishes, and never fabricate file bytes", mode_reviewed: "2026-09-02", tag: "Downloads" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/effective-branching-model", area: "branching-model", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity BranchingModel", mode_reviewed: "2026-09-01", tag: "Branching model" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/effective-default-reviewers", area: "pulls", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): the repository's own reviewers plus whatever the project adds, each row saying WHICH — `default_reviewer_and_type`. `reviewer_type` is \"repository\" on every row and that is DERIVED, not defaulted: canon writes approval rules at repository scope only, because the subgroup owns no repository and so has no merge to measure a policy from. Conformance asserts the effective list is exactly the repository list, which is what \"plus nothing from the project\" means, and turns red the day a project-scoped rule exists. An artifact that predates the domain answers the hello-17 generation gap: an empty default-reviewer list would say this repository automatically requests nobody, which is a claim about how this team reviews rather than about the snapshot the caller pinned.", mode_reviewed: "2026-09-12", tag: "Pullrequests" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/environments", area: "deployments", tier: 2, status: "green", mode: "derive", tag: "Deployments" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/environments/{environment_uuid}", area: "deployments", tier: 2, status: "green", mode: "derive", tag: "Deployments" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/file-conflicts/{spec}", area: "commits", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W3): the paths BOTH sides changed since their merge base, to different content - reader.treeFiles() over the same git blobs `/diff/{spec}` reads. A path one side left alone merges cleanly and a path both sides changed identically merges cleanly, so neither is reported, and `scenario` is delete_modify/modify_delete/content read off which side dropped the file. `message` is omitted: Bitbucket fills it from its merge engine and this host runs none. The 200 is a page envelope with no required member, so a spec whose sides merge cleanly is an honest empty page rather than an invented conflict", mode_reviewed: "2026-09-12", tag: "Commits" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/filehistory/{commit}/{path}", area: "source", tier: 1, status: "deviation", mode: "derive", tag: "Source" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/forks", area: "repos", tier: 1, status: "green", mode: "empty", mode_reason: "no repository in this universe is a fork and none has been forked: the workspace owns every repository and there is no account outside it to fork into", mode_reviewed: "2026-09-01", tag: "Repositories" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/hooks", area: "repos", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-18): Bitbucket's webhook_subscription over canon's webhook_subscription, which hello-18's features.webhookFilters widened from PagerDuty's three account scopes to the three a repository host publishes at — so a repository hook and a workspace hook are ONE object at two scopes, which is exactly why Bitbucket's own subject_type is an enum of those two words. THE EVENT NAMES ARE THIS RENDERER'S TRANSLATION, not canon's: canon's vocabulary is neutral because three renderers read that table, and Bitbucket spells the same six deliveries ref.pushed -> repo:push, change.opened -> pullrequest:created, change.merged -> pullrequest:fulfilled, issue.opened -> issue:created, issue.closed -> issue:updated and build.completed -> repo:commit_status_updated. Two of those needed an argument and both are recorded: Bitbucket publishes no `issue:closed` at all, and closing an issue IS an `issue:updated` in its vocabulary; and a build result on Bitbucket IS a commit status, reported by creating one when the build starts and UPDATING it when it finishes, which is the half canon records. Conformance re-derives the mapping independently of the renderer and asserts every served name is one the vendored enum publishes. `subject` is the condensed repository this host already serves at its own address, so a hook and the thing it is installed on cannot disagree (invariant #5), and conformance asserts the workspace's hook is NOT listed here. `secret_set` is FALSE and is sent, because canon states there is no signing secret; `secret` itself is never sent, which is also what real Bitbucket does. Gated on hasWebhookFilters(); an older artifact answers the named hello-18 webhook gap rather than an empty envelope, because an empty envelope there would say this team wires up nothing", mode_reviewed: "2026-09-12", tag: "Repositories" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/hooks/{uid}", area: "repos", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-18): the same hook by its braced uuid, byte-identical to the row the list publishes — conformance compares them directly. A WORKSPACE HOOK'S UUID IS A 404 HERE and a repository hook's is a 404 on the workspace path: the two scopes are different objects, and a host that resolved either id at either address would be publishing one subscription twice. Conformance drives both crossings. A uuid nobody holds is Bitbucket's own 404. Gated on hasWebhookFilters()", mode_reviewed: "2026-09-12", tag: "Repositories" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/issues", area: "issues-legacy", tier: 3, status: "excluded", mode: "unclassified", tag: "Issue tracker" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/issues/{issue_id}", area: "issues-legacy", tier: 3, status: "excluded", mode: "unclassified", tag: "Issue tracker" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/issues/{issue_id}/attachments", area: "issues-legacy", tier: 3, status: "excluded", mode: "unclassified", tag: "Issue tracker" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/issues/{issue_id}/attachments/{path}", area: "issues-legacy", tier: 3, status: "excluded", mode: "unclassified", tag: "Issue tracker" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/issues/{issue_id}/changes", area: "issues-legacy", tier: 3, status: "excluded", mode: "unclassified", tag: "Issue tracker" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/issues/{issue_id}/changes/{change_id}", area: "issues-legacy", tier: 3, status: "excluded", mode: "unclassified", tag: "Issue tracker" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/issues/{issue_id}/comments", area: "issues-legacy", tier: 3, status: "excluded", mode: "unclassified", tag: "Issue tracker" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/issues/{issue_id}/comments/{comment_id}", area: "issues-legacy", tier: 3, status: "excluded", mode: "unclassified", tag: "Issue tracker" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/issues/{issue_id}/vote", area: "issues-legacy", tier: 3, status: "excluded", mode: "unclassified", tag: "Issue tracker" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/issues/{issue_id}/watch", area: "issues-legacy", tier: 3, status: "excluded", mode: "unclassified", tag: "Issue tracker" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/issues/export/{repo_name}-issues-{task_id}.zip", area: "issues-legacy", tier: 3, status: "excluded", mode: "unclassified", tag: "Issue tracker" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/issues/import", area: "issues-legacy", tier: 3, status: "excluded", mode: "unclassified", tag: "Issue tracker" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/merge-base/{revspec}", area: "commits", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W3): reader.mergeBase(a,b) over the two commits the revspec names, rendered by the same renderCommit `/commit/{commit}` is green for - conformance asserts the two bodies are byte-identical and that the answer is an ancestor of both sides. A revspec naming ONE commit is Bitbucket's own documented 404: a merge base is a question about two sides, and one commit does not pose it", mode_reviewed: "2026-09-12", tag: "Commits" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/milestones", area: "issues-legacy", tier: 3, status: "excluded", mode: "unclassified", tag: "Issue tracker" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/milestones/{milestone_id}", area: "issues-legacy", tier: 3, status: "excluded", mode: "unclassified", tag: "Issue tracker" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/override-settings", area: "repos", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W3): `type` alone, which is the vendored schema's only required member and the whole of what this universe knows. `override_settings` enumerates the settings a repository has taken control of from its project; canon models no per-repository setting at all - every repository reports the same merge strategies and the same branch model because both are derived rather than stored - so there is nothing overridden to enumerate. Sending `{}` would claim the same thing less clearly and inventing booleans for settings canon does not carry is a placeholder", mode_reviewed: "2026-09-12", tag: "Repositories" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/patch/{spec}", area: "commits", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W3): a git format-patch series, raw text - the vendored operation declares a 200 with no content at all, so every line is asserted instead: the `From <sha>` lines are reader.commitsOnlyIn(source,destination) in git's own oldest-first order, the `From:`/`Date:`/`Subject:` headers are the commit's own author and instant, and each patch body IS the text `/diff/{sha}` serves for that commit. `Mon Sep 17 00:00:00 2001` is git's fixed mbox sentinel rather than a date, and the `-- <git version>` trailer is omitted because no git produced this patch", mode_reviewed: "2026-09-12", tag: "Commits" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/permissions-config/groups", area: "repos", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): the EXPLICIT group permissions on this repository — reader.teamGrants(\"repo\", repo), validated against `paginated_repository_group_permissions`. THIS ROW WAS RULED EMPTY BY THE FOUNDER ON 2026-09-10 on the claim that \"canon's Membership binds a PERSON to a container and never a team to one … no team-to-repository grant exists in any generation\", and that ruling said in as many words what would falsify it: the expectsEmpty entry fails \"the day canon grants a team access to a container\". hello-17 `grants` (decisions/2026-09-11-2304) lets a Membership name a TEAM as its principal: the team that owns the most components of a repository holds `maintainer` on it and a team that owns none but reviews it holds `member`, with ownership derived from the commit histogram. A Bitbucket GROUP is canon's TEAM on this host, so a group's explicit permission IS a team-principal grant. The permission comes through the same RoleVocabulary.repository map every other grant on this host goes through, so a team holding `maintainer` reports the same `admin` a person holding `maintainer` reports; conformance recomputes it from the role catalog and asserts no team-principal row leaks into /permissions-config/users and no person into this list. EVERY REGISTERED PIN ANSWERS EXACTLY AS IT DID BEFORE THIS WAVE. The route carries no generation gate: it reads reader.teamGrants()/reader.namespaceMembers(), which return [] on any artifact whose canon has no such row, so a -g11 pin goes on sending the same empty page and goes on saying something true about the universe it holds. What changed is the ARGUMENT — the emptiness was called a property of the MODEL and is now a property of each ARTIFACT — and packages/conformance/src/bitbucket/access.test.ts asserts the pin answer on hello-16, hello-15 and hello-4.", mode_reviewed: "2026-09-12", tag: "Repositories" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/permissions-config/groups/{group_slug}", area: "repos", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): one group's explicit permission on this repository, addressed by the TEAM SLUG this host publishes everywhere else. Re-slugging the team name here would mint a second identity for one team and the two could then disagree, so `slug` is canon's own and `full_slug` is Bitbucket's `workspace:group` form built from the two slugs. hello-17 `grants` (decisions/2026-09-11-2304) lets a Membership name a TEAM as its principal: the team that owns the most components of a repository holds `maintainer` on it and a team that owns none but reviews it holds `member`, with ownership derived from the commit histogram. A Bitbucket GROUP is canon's TEAM on this host, so a group's explicit permission IS a team-principal grant. A slug that names no team, and a team that holds no grant on this repository, are both Bitbucket's own 404 — the rule the user twin follows, because `none` is what a WRITE removes a grant with and not what a read returns for somebody who holds nothing. Conformance drives both negatives. Answers the honest 404 on an artifact with no team grant, because the parent list is empty there and no group_slug resolves", mode_reviewed: "2026-09-12", tag: "Repositories" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/permissions-config/users", area: "repos", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): the EXPLICIT grants on this repository — reader.listMemberships(\"repo\", repo) (packages/artifact/src/reader.ts:2961), validated against `paginated_repository_user_permissions`. Canon writes a repository-scoped membership ONLY where the repository's roster genuinely differs from the organization's (rule 5, packages/generator/src/access.ts), which is exactly what Bitbucket means by \"explicit\" — so the list is short and every row in it says something the workspace roster does not. Canon's five role keys reach Bitbucket's `admin`/`write`/`read` through ONE map (packages/renderer-bitbucket/src/render-access.ts) read off the role catalog's own `repo:` rung rather than a hand-written table; conformance recomputes it and asserts this list is a strict SUBSET of the effective one", mode_reviewed: "2026-09-09", tag: "Repositories" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/permissions-config/users/{selected_user_id}", area: "repos", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): one explicit grant, addressed by the account UUID or Atlassian account id this host already resolves users by — reader.membershipFor(\"repo\", repo, person) (reader.ts:2977). A person with no explicit grant on this repository is Bitbucket's own 404 rather than a `permission: \"none\"` row: `none` is what a WRITE removes a grant with, and their effective permission is still published by /workspaces/{workspace}/permissions/repositories/{repo_slug}. Conformance asserts both halves against the same artifact", mode_reviewed: "2026-09-09", tag: "Repositories" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pipelines", area: "pipelines", tier: 2, status: "green", mode: "derive", tag: "Pipelines" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pipelines_config", area: "pipelines", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsPolicy", mode_reviewed: "2026-09-01", tag: "Pipelines" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pipelines_config/schedules", area: "pipelines", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09: reader.listWorkflowSchedules(repo) (packages/artifact/src/reader.ts:2297), rendered as `pipeline_schedule` and validated against the vendored `paginated_pipeline_schedules`. `cron_pattern` is canon's (per_hour, hours_of_day, days_of_week) triple re-encoded as the seven Quartz fields the document asks for — lossless, and the conformance entry re-derives it; `target.ref_name` is the branch canon points at, and the test fetches it back through /refs/branches to prove it resolves (invariant #5). `enabled` is true because every schedule here started real runs. Answers the hello-15 generation gap on an older artifact rather than an empty envelope", mode_reviewed: "2026-09-09", tag: "Pipelines" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pipelines_config/schedules/{schedule_uuid}", area: "pipelines", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09: reader.workflowSchedule(id) (packages/artifact/src/reader.ts:2302), byte-identical to the row the list serves — asserted, so the two addressings cannot drift. A uuid this repository does not hold is Bitbucket's own 404", mode_reviewed: "2026-09-09", tag: "Pipelines" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pipelines_config/schedules/{schedule_uuid}/executions", area: "pipelines", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09: reader.runsForSchedule(id) (packages/artifact/src/reader.ts:2839), reading workflow_run.schedule directly, as `pipeline_schedule_execution_executed` — the variant the vendored spec declares, whose only members are the discriminator and `pipeline`. Each pipeline is BYTE-IDENTICAL to what GET /pipelines/{uuid} serves for the same run (the conformance entry fetches it back and compares), and every run it returns carries event `schedule`. The errored variant is never emitted: canon records no schedule that failed to start a pipeline", mode_reviewed: "2026-09-09", tag: "Pipelines" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pipelines_config/ssh/key_pair", area: "pipelines", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity PipelineSshKey", mode_reviewed: "2026-09-01", tag: "Pipelines" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pipelines_config/ssh/known_hosts", area: "pipelines", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity PipelineSshKey", mode_reviewed: "2026-09-01", tag: "Pipelines" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pipelines_config/ssh/known_hosts/{known_host_uuid}", area: "pipelines", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity PipelineSshKey", mode_reviewed: "2026-09-01", tag: "Pipelines" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pipelines_config/variables", area: "pipelines", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` - the same canon GitHub serves as Actions secrets and variables, in Bitbucket's dialect. `secured` IS canon's `masked`, so the two hosts cannot disagree about which of this organization's settings may be published, and `value` is `\"\"` on a secured row because the vendored property description says so in as many words (\"If the variable is secured, this will be empty\") - canon holds NO value for a masked binding, so the empty string is composed at the boundary from the absence. The repository's own pipeline variables, four of them: two credential-backed secrets (the registry pull token, and the integration-suite token whose two dates are a rotation canon records) and two published settings read from the rows they name", mode_reviewed: "2026-09-12", tag: "Pipelines" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pipelines_config/variables/{variable_uuid}", area: "pipelines", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` - the same canon GitHub serves as Actions secrets and variables, in Bitbucket's dialect. `secured` IS canon's `masked`, so the two hosts cannot disagree about which of this organization's settings may be published, and `value` is `\"\"` on a secured row because the vendored property description says so in as many words (\"If the variable is secured, this will be empty\") - canon holds NO value for a masked binding, so the empty string is composed at the boundary from the absence. Addressed by the `bbUuid` the list publishes, so the id a caller walks to is the id this route accepts. A uuid this repository does not hold is Bitbucket's own 404", mode_reviewed: "2026-09-12", tag: "Pipelines" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pipelines-config/caches", area: "pipelines", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsCache", mode_reviewed: "2026-09-01", tag: "Pipelines" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pipelines-config/caches/{cache_uuid}/content-uri", area: "pipelines", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsCache", mode_reviewed: "2026-09-01", tag: "Pipelines" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pipelines-config/runners", area: "pipelines", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Runner", mode_reviewed: "2026-09-01", tag: "Pipelines" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pipelines-config/runners/{runner_uuid}", area: "pipelines", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Runner", mode_reviewed: "2026-09-01", tag: "Pipelines" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pipelines/{pipeline_uuid}", area: "pipelines", tier: 2, status: "green", mode: "derive", tag: "Pipelines" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pipelines/{pipeline_uuid}/steps", area: "pipelines", tier: 2, status: "green", mode: "derive", tag: "Pipelines" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pipelines/{pipeline_uuid}/steps/{step_uuid}", area: "pipelines", tier: 2, status: "green", mode: "derive", tag: "Pipelines" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pipelines/{pipeline_uuid}/steps/{step_uuid}/log", area: "pipelines", tier: 2, status: "green", mode: "derive", mode_reason: "the step log has served reader.jobLogText(job) since #311; the row was still `generate` only because no conformance entry drove it", mode_reviewed: "2026-09-02", tag: "Pipelines" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pipelines/{pipeline_uuid}/steps/{step_uuid}/logs/{log_uuid}", area: "pipelines", tier: 2, status: "green", mode: "derive", mode_reason: "the build-container variant of the same log - the document defines log_uuid as the step UUID for the main build container, and those bytes are reader.jobLogText(job). This universe models no service containers, so any other log_uuid is a 404", mode_reviewed: "2026-09-02", tag: "Pipelines" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pipelines/{pipeline_uuid}/steps/{step_uuid}/test_reports", area: "pipelines", tier: 2, status: "deferred", mode: "derive", mode_reason: "the report is the AGGREGATE of reader.testResultsForJob(job) (packages/artifact/src/reader.ts:2320): hello-15's canon.TestResult (packages/canon/src/ci-config.ts:204) carries a status and a duration per case, so the pass/fail/skip counts are a fold over rows that exist. The 2026-09-09 serving wave did NOT build this row, and the reason is a spec gap rather than canon: the vendored swagger declares a 200 with NO content block and NO test_* component for it, and Atlassian publishes no response body for it anywhere a capture could cite. Atlassian's own KB names three summary fields (number_of_test_cases, number_of_failed_test_cases, number_of_successful_test_cases, in a working jq example) and nothing more, so any further field would be invented — which is what invariant #4 forbids and what the DECISIONS §P17 Wave B `shape` pattern requires documented evidence to avoid. The row needs a CAPTURE, not a canon entity", mode_reviewed: "2026-09-09", tag: "Pipelines" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pipelines/{pipeline_uuid}/steps/{step_uuid}/test_reports/test_cases", area: "pipelines", tier: 2, status: "deferred", mode: "derive", mode_reason: "reader.listTestCases(repo) (packages/artifact/src/reader.ts:2308) joined to reader.testResultsForJob(job) (:2320): canon.TestCase (packages/canon/src/ci-config.ts:156) is the DEFINITION and TestResult is this job's run of it. The 2026-09-09 serving wave did NOT build this row, and the reason is a spec gap rather than canon: the vendored swagger declares a 200 with NO content block and NO test_* component for it, and Atlassian publishes no response body for it anywhere a capture could cite. Atlassian's own KB names three summary fields (number_of_test_cases, number_of_failed_test_cases, number_of_successful_test_cases, in a working jq example) and nothing more, so any further field would be invented — which is what invariant #4 forbids and what the DECISIONS §P17 Wave B `shape` pattern requires documented evidence to avoid. The row needs a CAPTURE, not a canon entity", mode_reviewed: "2026-09-09", tag: "Pipelines" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pipelines/{pipeline_uuid}/steps/{step_uuid}/test_reports/test_cases/{test_case_uuid}/test_case_reasons", area: "pipelines", tier: 2, status: "deferred", mode: "derive", mode_reason: "the failure text of one case in one job — reader.testResultsForJob(job) (packages/artifact/src/reader.ts:2320) filtered to the case; canon.TestResult.messageSlot (packages/canon/src/ci-config.ts:213) is the theme's per-status message, set exactly on failure and error. The 2026-09-09 serving wave did NOT build this row, and the reason is a spec gap rather than canon: the vendored swagger declares a 200 with NO content block and NO test_* component for it, and Atlassian publishes no response body for it anywhere a capture could cite. Atlassian's own KB names three summary fields (number_of_test_cases, number_of_failed_test_cases, number_of_successful_test_cases, in a working jq example) and nothing more, so any further field would be invented — which is what invariant #4 forbids and what the DECISIONS §P17 Wave B `shape` pattern requires documented evidence to avoid. The row needs a CAPTURE, not a canon entity", mode_reviewed: "2026-09-09", tag: "Pipelines" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/properties/{app_key}/{property_name}", area: "addon-properties", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no Atlassian Connect app is installed on this workspace; these routes are addressed to an installed app's own key scope and Bitbucket answers 404 to a caller that is not that app (the ruled Jira Connect/Forge precedent, coverage/reviews/2026-09-01-jira-modes.md row 1)", mode_reviewed: "2026-09-01", tag: "properties" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pullrequests", area: "pulls", tier: 1, status: "green", mode: "derive", tag: "Pullrequests" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pullrequests/{pull_request_id}", area: "pulls", tier: 1, status: "green", mode: "derive", tag: "Pullrequests" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pullrequests/{pull_request_id}/activity", area: "pulls", tier: 1, status: "green", mode: "derive", tag: "Pullrequests" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pullrequests/{pull_request_id}/comments", area: "pulls", tier: 1, status: "green", mode: "derive", tag: "Pullrequests" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pullrequests/{pull_request_id}/comments/{comment_id}", area: "pulls", tier: 1, status: "green", mode: "derive", tag: "Pullrequests" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pullrequests/{pull_request_id}/commits", area: "pulls", tier: 1, status: "green", mode: "derive", tag: "Pullrequests" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pullrequests/{pull_request_id}/conflicts", area: "pulls", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W3): the documented 302 to `/file-conflicts/{baseTip}..{head}`. The revspec names the two TIPS and never the merge base, which is the whole judgment on this row: a merge base conflicts with the head on nothing by construction, so a redirect naming it would always answer an empty page. The base tip is the merge commit's first parent on a merged pull and the base branch's head on an open one - the same instant reader.pullDiffRange resolves the base from", mode_reviewed: "2026-09-12", tag: "Pullrequests" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pullrequests/{pull_request_id}/diff", area: "pulls", tier: 1, status: "green", mode: "derive", tag: "Pullrequests" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pullrequests/{pull_request_id}/diffstat", area: "pulls", tier: 1, status: "green", mode: "derive", tag: "Pullrequests" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pullrequests/{pull_request_id}/merge/task-status/{task_id}", area: "pulls", tier: 1, status: "planned", mode: "refuse", mode_reason: "this universe accepts no writes, so no merge was ever queued and no task id relates to this pull request - Bitbucket's own 400 for such a task id is the whole answer (the operation declares 400/403/409 and no 404, and its 400 description IS the ruled condition: \"If the provided task ID does not relate to this pull request\"; founder ruling 2026-09-03 on proposal 1 of coverage/reviews/2026-09-03-bitbucket-refuse-shapes.md, superseding the 404 read from the Jira async-job precedent)", mode_reviewed: "2026-09-03", tag: "Pullrequests" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pullrequests/{pull_request_id}/patch", area: "pulls", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W3): the documented 302 to `/patch/{head}..{mergeBase}` - SOURCE first, which is the order the patch operation documents ('the first commit represents the source') and what makes the series the pull's own commits. Conformance follows the redirect and asserts the series carries exactly the commits `/pullrequests/{id}/commits` lists", mode_reviewed: "2026-09-12", tag: "Pullrequests" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pullrequests/{pull_request_id}/statuses", area: "pulls", tier: 1, status: "green", mode: "derive", tag: "Pullrequests" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pullrequests/{pull_request_id}/tasks", area: "pulls", tier: 1, status: "planned", mode: "generate", mode_reason: "new canon entity PullTask", mode_reviewed: "2026-09-01", tag: "Pullrequests" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pullrequests/{pull_request_id}/tasks/{task_id}", area: "pulls", tier: 1, status: "planned", mode: "generate", mode_reason: "new canon entity PullTask", mode_reviewed: "2026-09-01", tag: "Pullrequests" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pullrequests/{pullrequest_id}/properties/{app_key}/{property_name}", area: "addon-properties", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no Atlassian Connect app is installed on this workspace; these routes are addressed to an installed app's own key scope and Bitbucket answers 404 to a caller that is not that app (the ruled Jira Connect/Forge precedent, coverage/reviews/2026-09-01-jira-modes.md row 1)", mode_reviewed: "2026-09-01", tag: "properties" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/pullrequests/activity", area: "pulls", tier: 1, status: "green", mode: "derive", tag: "Pullrequests" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/refs", area: "refs", tier: 1, status: "green", mode: "derive", tag: "Refs" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/refs/branches", area: "refs", tier: 1, status: "green", mode: "derive", tag: "Refs" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/refs/branches/{name}", area: "refs", tier: 1, status: "green", mode: "derive", tag: "Refs" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/refs/tags", area: "refs", tier: 1, status: "green", mode: "derive", tag: "Refs" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/refs/tags/{name}", area: "refs", tier: 1, status: "green", mode: "derive", tag: "Refs" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/src", area: "source", tier: 1, status: "green", mode: "derive", tag: "Source" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/src/{commit}/{path}", area: "source", tier: 1, status: "green", mode: "derive", tag: "Source" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/versions", area: "issues-legacy", tier: 3, status: "excluded", mode: "unclassified", tag: "Issue tracker" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/versions/{version_id}", area: "issues-legacy", tier: 3, status: "excluded", mode: "unclassified", tag: "Issue tracker" }
      - { method: "GET", path: "/repositories/{workspace}/{repo_slug}/watchers", area: "repos", tier: 1, status: "planned", mode: "generate", mode_reason: "new canon entity RepoSubscription", mode_reviewed: "2026-09-01", tag: "Repositories" }
      - { method: "GET", path: "/snippets", area: "snippets", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Snippet", mode_reviewed: "2026-09-01", tag: "Snippets" }
      - { method: "GET", path: "/snippets/{workspace}", area: "snippets", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Snippet", mode_reviewed: "2026-09-01", tag: "Snippets" }
      - { method: "GET", path: "/snippets/{workspace}/{encoded_id}", area: "snippets", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Snippet", mode_reviewed: "2026-09-01", tag: "Snippets" }
      - { method: "GET", path: "/snippets/{workspace}/{encoded_id}/{node_id}", area: "snippets", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Snippet", mode_reviewed: "2026-09-01", tag: "Snippets" }
      - { method: "GET", path: "/snippets/{workspace}/{encoded_id}/{node_id}/files/{path}", area: "snippets", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Snippet", mode_reviewed: "2026-09-01", tag: "Snippets" }
      - { method: "GET", path: "/snippets/{workspace}/{encoded_id}/{revision}/diff", area: "snippets", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Snippet", mode_reviewed: "2026-09-01", tag: "Snippets" }
      - { method: "GET", path: "/snippets/{workspace}/{encoded_id}/{revision}/patch", area: "snippets", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Snippet", mode_reviewed: "2026-09-01", tag: "Snippets" }
      - { method: "GET", path: "/snippets/{workspace}/{encoded_id}/comments", area: "snippets", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Snippet", mode_reviewed: "2026-09-01", tag: "Snippets" }
      - { method: "GET", path: "/snippets/{workspace}/{encoded_id}/comments/{comment_id}", area: "snippets", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Snippet", mode_reviewed: "2026-09-01", tag: "Snippets" }
      - { method: "GET", path: "/snippets/{workspace}/{encoded_id}/commits", area: "snippets", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Snippet", mode_reviewed: "2026-09-01", tag: "Snippets" }
      - { method: "GET", path: "/snippets/{workspace}/{encoded_id}/commits/{revision}", area: "snippets", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Snippet", mode_reviewed: "2026-09-01", tag: "Snippets" }
      - { method: "GET", path: "/snippets/{workspace}/{encoded_id}/files/{path}", area: "snippets", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Snippet", mode_reviewed: "2026-09-01", tag: "Snippets" }
      - { method: "GET", path: "/snippets/{workspace}/{encoded_id}/watch", area: "snippets", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity RepoSubscription", mode_reviewed: "2026-09-01", tag: "Snippets" }
      - { method: "GET", path: "/snippets/{workspace}/{encoded_id}/watchers", area: "snippets", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity RepoSubscription", mode_reviewed: "2026-09-01", tag: "Snippets" }
      - { method: "GET", path: "/teams/{username}/pipelines_config/variables", area: "pipelines", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` - the same canon GitHub serves as Actions secrets and variables, in Bitbucket's dialect. `secured` IS canon's `masked`, so the two hosts cannot disagree about which of this organization's settings may be published, and `value` is `\"\"` on a secured row because the vendored property description says so in as many words (\"If the variable is secured, this will be empty\") - canon holds NO value for a masked binding, so the empty string is composed at the boundary from the absence. The legacy team path addresses the WORKSPACE account, which owns every repository in this universe, so it answers `/workspaces/{workspace}/pipelines-config/variables` BYTE-IDENTICALLY through the same closure - the ruling `/teams/{username}/search/code` already set on 2026-09-12, and conformance asserts the two agree rather than letting two paths for one account drift", mode_reviewed: "2026-09-12", tag: "Pipelines" }
      - { method: "GET", path: "/teams/{username}/pipelines_config/variables/{variable_uuid}", area: "pipelines", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` - the same canon GitHub serves as Actions secrets and variables, in Bitbucket's dialect. `secured` IS canon's `masked`, so the two hosts cannot disagree about which of this organization's settings may be published, and `value` is `\"\"` on a secured row because the vendored property description says so in as many words (\"If the variable is secured, this will be empty\") - canon holds NO value for a masked binding, so the empty string is composed at the boundary from the absence. The by-uuid half of the same alias, through the same closure as the workspace route", mode_reviewed: "2026-09-12", tag: "Pipelines" }
      - { method: "GET", path: "/teams/{username}/search/code", area: "search", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W3): the legacy team path addresses the WORKSPACE account, which owns every repository in this universe, so it answers `/workspaces/{workspace}/search/code` byte-identically - conformance asserts exactly that, rather than letting two paths for one account drift", mode_reviewed: "2026-09-12", tag: "Search" }
      - { method: "GET", path: "/user", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W3): the route was REGISTERED in wave A and never asserted, which is the whole of this row: renderUser(viewer()), the workspace's founding member. Conformance now asserts it is that person, that `/2.0/users/{uuid}` renders the identical account, and that `/2.0/user/emails` carries the same person's address - the caller-scoped surfaces on this host all report one identity or two of them describe two accounts", mode_reviewed: "2026-09-12", tag: "Users" }
      - { method: "GET", path: "/user/emails", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): the authenticated caller's addresses — reader.credentialsForPerson(viewer, \"email\") (packages/artifact/src/reader.ts:3016). The caller is whoever GET /user already resolves to, read from ONE function so this host cannot disagree with itself about whose addresses these are. `is_confirmed` is the credential's own state rather than a decision, and exactly one address is primary — conformance asserts both and follows every `links.self` back to the single-address row. The vendored swagger declares NO 200 for this operation (only a `default` error), a documented Bitbucket spec gap, so the entry asserts the documented live shape plus canon consistency instead of a schema", mode_reviewed: "2026-09-09", tag: "Users" }
      - { method: "GET", path: "/user/emails/{email}", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): one of the caller's addresses by its text, byte-identical to the row the list serves — conformance follows `links.self` from every list row and compares. An address the caller does not hold is Bitbucket's own 404. Same spec gap as the list: no 200 is declared, so the shape assertion is the gate", mode_reviewed: "2026-09-09", tag: "Users" }
      - { method: "GET", path: "/user/permissions/repositories", area: "repos", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): the caller's EFFECTIVE permission on each repository — \"the highest level of permission the user has … does not distinguish between direct and indirect (group) privileges\", which is the maximum of the rung their org role gives and the rung any direct repository membership gives, taken in ONE place (packages/renderer-bitbucket/src/render-access.ts) off reader.listMemberships (reader.ts:2961). Bitbucket marks this operation DEPRECATED in favour of the workspace-scoped one; both are served and conformance asserts their `values` are byte-identical, because this workspace owns every repository the artifact carries", mode_reviewed: "2026-09-09", tag: "Repositories" }
      - { method: "GET", path: "/user/permissions/workspaces", area: "workspaces", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): the caller's own workspace membership — reader.listMemberships(\"org\", org) (reader.ts:2961) narrowed to whoever GET /user resolves to. `owner` exactly when the role catalog gives that role `org:admin`, which is a rung the ARTIFACT carries rather than a table copied into the renderer; conformance recomputes it. `collaborator` is never produced, because nobody in this universe is outside the workspace — every person carries member = 1 — and Atlassian is removing the role from the API anyway. Conformance asserts this single row is byte-identical to /user/workspaces/{workspace}/permission", mode_reviewed: "2026-09-09", tag: "Workspaces" }
      - { method: "GET", path: "/user/workspaces", area: "workspaces", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W3): the workspaces the caller can reach, with whether they administer each - reader.listMemberships('org', org) restricted to the viewer, `administrator` being `org:admin` read through the artifact's role catalog. The embedded object is `workspace_base`, whose links member declares self and avatar and forbids the rest, so the richer block condensedWorkspace carries is deliberately not used here. Behind the hello-16 membership gate for the reason `/user/permissions/workspaces` is: `administrator` is a PERMISSION, and `false` on an older pin would be a claim about the caller rather than about the snapshot", mode_reviewed: "2026-09-12", tag: "Workspaces" }
      - { method: "GET", path: "/user/workspaces/{workspace}/permission", area: "workspaces", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): the caller's effective workspace role as one `workspace_membership` — reader.membershipFor(\"org\", org, person) (reader.ts:2977), byte-identical to the single row /user/permissions/workspaces returns and asserted so. A workspace slug this host does not serve is the ordinary 404, checked separately from the generation gap so a typo never reads as a missing generation", mode_reviewed: "2026-09-09", tag: "Workspaces" }
      - { method: "GET", path: "/user/workspaces/{workspace}/permissions/repositories", area: "repos", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): the workspace-scoped replacement Bitbucket points the deprecated /user/permissions/repositories at, and the same effective permissions — this workspace owns every repository the artifact carries, which is a fact about the universe rather than a shortcut: the resolution still goes through the workspace, so a slug that names none 404s. Conformance asserts the two bodies agree", mode_reviewed: "2026-09-09", tag: "Repositories" }
      - { method: "GET", path: "/users/{selected_user}", area: "users", tier: 1, status: "green", mode: "derive", tag: "Users" }
      - { method: "GET", path: "/users/{selected_user}/gpg-keys", area: "ssh-gpg", tier: 3, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): a person's PERSONAL OpenPGP keys — reader.credentialsForPerson(user, \"gpg\") (reader.ts:3016). `key_id` and `fingerprint` are the artifact's own, and conformance RECOMPUTES the fingerprint from the packet the way GnuPG does (SHA-1 over 0x99‖len‖body) and checks the key id is its last eight bytes. The armored `key` is NOT served: a transferable OpenPGP key needs a user id and a self-signature, a self-signature needs a private half this universe never generated, and the field is opt-in on Bitbucket's own operation — #430's `raw_key: null` reasoning in Bitbucket's spelling, asserted ABSENT rather than left to be noticed. The WORKSPACE key is excluded here and served once at /workspaces/{workspace}/settings/gpg/public-key. `deviation` rather than green: the vendored schema types `parent_fingerprint` `string` while its own description says the value is null unless the key is a subkey, and every key here is a primary key", mode_reviewed: "2026-09-09", tag: "GPG" }
      - { method: "GET", path: "/users/{selected_user}/gpg-keys/{fingerprint}", area: "ssh-gpg", tier: 3, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): one personal GPG key by its v4 fingerprint, byte-identical to the row the list serves. A fingerprint this person does not hold is Bitbucket's own 404. `deviation` for the same vendored `parent_fingerprint` contradiction as the list", mode_reviewed: "2026-09-09", tag: "GPG" }
      - { method: "GET", path: "/users/{selected_user}/pipelines_config/variables", area: "pipelines", tier: 2, status: "green", mode: "empty", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a) as Bitbucket's empty page at 200: this path addresses a PERSON, and no person in this universe owns a repository or runs a pipeline of their own - so there is nothing for a person-scoped pipeline variable to configure. The WORKSPACE's variables are deliberately NOT served here; that is what the `/teams/{username}` alias is for, and serving one under the other's name is the confusion the hello-19 seed brief flagged (§G5). UNGATED across generations, for the same reason `/users/{selected_user}/search/code` is: repository ownership is a property of the model rather than of a feature flag", mode_reviewed: "2026-09-12", tag: "Pipelines" }
      - { method: "GET", path: "/users/{selected_user}/pipelines_config/variables/{variable_uuid}", area: "pipelines", tier: 2, status: "deferred", mode: "refuse", mode_reason: "REFUSED 2026-09-12 (hello-19 wave W-a) with Bitbucket's own 404: no uuid resolves over the empty collection its list half answers - see that row", mode_reviewed: "2026-09-12", tag: "Pipelines" }
      - { method: "GET", path: "/users/{selected_user}/properties/{app_key}/{property_name}", area: "addon-properties", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no Atlassian Connect app is installed on this workspace; these routes are addressed to an installed app's own key scope and Bitbucket answers 404 to a caller that is not that app (the ruled Jira Connect/Forge precedent, coverage/reviews/2026-09-01-jira-modes.md row 1)", mode_reviewed: "2026-09-01", tag: "properties" }
      - { method: "GET", path: "/users/{selected_user}/search/code", area: "search", tier: 3, status: "green", mode: "empty", mode_reason: "no person in this organization owns a repository — the workspace owns every one of them, which is what /workspaces/{workspace}/search/code searches; Bitbucket's own answer for an account with no matching code is the search page with `size: 0`. THE PERSON STILL RESOLVES and the query is still required: a selected_user nobody has is Bitbucket's 404 rather than an empty page, and a request with no `search_query` is still the documented 400 — an honest empty answers the question that was asked, and a request with no query asked none. Conformance asserts the WORKSPACE search over the same term is NOT empty, so the emptiness is about who owns the repositories rather than about the query, and re-reads every repository's own owner to check the fact the ruling rests on. UNGATED: repository ownership is a property of the model — renderOwner is the workspace on every repository object in every generation — so all 127 registered pins answer this same empty page. RULED by the founder 2026-09-12 (round 20)", mode_reviewed: "2026-09-12", tag: "Search" }
      - { method: "GET", path: "/users/{selected_user}/ssh-keys", area: "ssh-gpg", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): a person's ACCESS keys — reader.credentialsForPerson(user, \"ssh-auth\") (reader.ts:3016). Canon's `ssh-signing` rows are deliberately excluded and this host publishes them nowhere: a key authorised to push and a key trusted to attest authorship are different grants (packages/canon/src/credentials.ts), Bitbucket Cloud has one account SSH surface and it is the ACCESS one, and serving a signing key here would assert a grant nobody made. The served `key` and `comment` are a SPLIT of the artifact's single OpenSSH line, so they can never describe different bytes, and conformance re-hashes the served line and asserts it reproduces the artifact's own `fingerprint_sha256` — the check a client runs with `ssh-keygen -lf`", mode_reviewed: "2026-09-09", tag: "SSH" }
      - { method: "GET", path: "/users/{selected_user}/ssh-keys/{key_id}", area: "ssh-gpg", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): one access key by its UUID (the spec's own words for `key_id`: \"the SSH key's UUID value\"), byte-identical to the row the list serves. A signing key's UUID does NOT address it, which is the same exclusion the list makes and is asserted from both sides", mode_reviewed: "2026-09-09", tag: "SSH" }
      - { method: "GET", path: "/workspaces", area: "workspaces", tier: 1, status: "green", mode: "derive", tag: "Workspaces" }
      - { method: "GET", path: "/workspaces/{workspace}", area: "workspaces", tier: 1, status: "green", mode: "derive", tag: "Workspaces" }
      - { method: "GET", path: "/workspaces/{workspace}/hooks", area: "workspaces", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-18): Bitbucket's webhook_subscription over canon's webhook_subscription, which hello-18's features.webhookFilters widened from PagerDuty's three account scopes to the three a repository host publishes at — so a repository hook and a workspace hook are ONE object at two scopes, which is exactly why Bitbucket's own subject_type is an enum of those two words. THE EVENT NAMES ARE THIS RENDERER'S TRANSLATION, not canon's: canon's vocabulary is neutral because three renderers read that table, and Bitbucket spells the same six deliveries ref.pushed -> repo:push, change.opened -> pullrequest:created, change.merged -> pullrequest:fulfilled, issue.opened -> issue:created, issue.closed -> issue:updated and build.completed -> repo:commit_status_updated. Two of those needed an argument and both are recorded: Bitbucket publishes no `issue:closed` at all, and closing an issue IS an `issue:updated` in its vocabulary; and a build result on Bitbucket IS a commit status, reported by creating one when the build starts and UPDATING it when it finishes, which is the half canon records. Conformance re-derives the mapping independently of the renderer and asserts every served name is one the vendored enum publishes. This is the ACCOUNT-WIDE feed — a different canonical row from the repository's, and a different row again from PagerDuty's account-scoped subscription, which is why the widened vocabulary carries all three. `subject` is the condensed workspace this host serves at its own address, and conformance asserts the repository's hook is NOT listed here. `secret_set` is FALSE and is sent, because canon states there is no signing secret; `secret` itself is never sent, which is also what real Bitbucket does. Gated on hasWebhookFilters(); an older artifact answers the named hello-18 webhook gap rather than an empty envelope, because an empty envelope there would say this team wires up nothing", mode_reviewed: "2026-09-12", tag: "Workspaces" }
      - { method: "GET", path: "/workspaces/{workspace}/hooks/{uid}", area: "workspaces", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-18): the same workspace hook by its braced uuid, byte-identical to the row the list publishes. A repository hook's uuid is Bitbucket's 404 here, which conformance drives from both sides. Gated on hasWebhookFilters()", mode_reviewed: "2026-09-12", tag: "Workspaces" }
      - { method: "GET", path: "/workspaces/{workspace}/members", area: "workspaces", tier: 1, status: "green", mode: "derive", tag: "Workspaces" }
      - { method: "GET", path: "/workspaces/{workspace}/members/{member}", area: "workspaces", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W3): registered beside the green `/workspaces/{workspace}/members` and, like `/user`, never asserted until now: renderMembership over the person a uuid or login names. Conformance asserts the user and workspace it names are the artifact's own", mode_reviewed: "2026-09-12", tag: "Workspaces" }
      - { method: "GET", path: "/workspaces/{workspace}/permissions", area: "workspaces", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): the workspace roster with each member's effective role — reader.listMemberships(\"org\", org) (reader.ts:2961) restricted to `active`, validated against `paginated_workspace_memberships`. The two PENDING invitations canon carries are excluded, and asserted excluded: an offer nobody accepted is not a member, and Bitbucket's own words are \"the list of members in a workspace\" (this host publishes no invitation surface, because Bitbucket Cloud has none). Conformance asserts the people here are exactly the people /workspaces/{workspace}/members lists, walks page/pagelen/next to the last page, and recomputes every permission from the role catalog", mode_reviewed: "2026-09-09", tag: "Workspaces" }
      - { method: "GET", path: "/workspaces/{workspace}/permissions/repositories", area: "workspaces", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): every (person, repository) EFFECTIVE permission in the workspace. Every member appears on every repository and that is not padding — canon's `member` role carries `repo:write` and this workspace owns every repository, so every member really can push to each one; a shorter list would be a different claim. `repo:maintain` collapses UP to Bitbucket's `admin` rather than to `write`, because branch restrictions and repository configuration — what canon's `maintainer` is FOR — are what Bitbucket's admin grants and its write does not; conformance asserts at least one row is therefore HIGHER than the person's org role alone gives, which is what makes canon's repository-scoped memberships visible on this host at all", mode_reviewed: "2026-09-09", tag: "Workspaces" }
      - { method: "GET", path: "/workspaces/{workspace}/permissions/repositories/{repo_slug}", area: "workspaces", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): the same effective permissions for ONE repository, through the same maximum. The repository is resolved by slug or braced UUID exactly as every other repository route on this host resolves it, so a slug that names none is the ordinary 404 rather than an empty page", mode_reviewed: "2026-09-09", tag: "Workspaces" }
      - { method: "GET", path: "/workspaces/{workspace}/pipelines-config/identity/oidc/.well-known/openid-configuration", area: "pipelines", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity PipelineOidcConfig", mode_reviewed: "2026-09-01", tag: "Pipelines" }
      - { method: "GET", path: "/workspaces/{workspace}/pipelines-config/identity/oidc/keys.json", area: "pipelines", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity PipelineOidcConfig", mode_reviewed: "2026-09-01", tag: "Pipelines" }
      - { method: "GET", path: "/workspaces/{workspace}/pipelines-config/runners", area: "pipelines", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Runner", mode_reviewed: "2026-09-01", tag: "Pipelines" }
      - { method: "GET", path: "/workspaces/{workspace}/pipelines-config/runners/{runner_uuid}", area: "pipelines", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Runner", mode_reviewed: "2026-09-01", tag: "Pipelines" }
      - { method: "GET", path: "/workspaces/{workspace}/pipelines-config/variables", area: "pipelines", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` - the same canon GitHub serves as Actions secrets and variables, in Bitbucket's dialect. `secured` IS canon's `masked`, so the two hosts cannot disagree about which of this organization's settings may be published, and `value` is `\"\"` on a secured row because the vendored property description says so in as many words (\"If the variable is secured, this will be empty\") - canon holds NO value for a masked binding, so the empty string is composed at the boundary from the absence. The workspace account's own variables - canon's organization scope", mode_reviewed: "2026-09-12", tag: "Pipelines" }
      - { method: "GET", path: "/workspaces/{workspace}/pipelines-config/variables/{variable_uuid}", area: "pipelines", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-19 wave W-a): `ci_binding` - the same canon GitHub serves as Actions secrets and variables, in Bitbucket's dialect. `secured` IS canon's `masked`, so the two hosts cannot disagree about which of this organization's settings may be published, and `value` is `\"\"` on a secured row because the vendored property description says so in as many words (\"If the variable is secured, this will be empty\") - canon holds NO value for a masked binding, so the empty string is composed at the boundary from the absence. Addressed by the uuid the list publishes", mode_reviewed: "2026-09-12", tag: "Pipelines" }
      - { method: "GET", path: "/workspaces/{workspace}/projects", area: "workspaces", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W3): the ONE project every repository has advertised in its `project` member since wave A, expanded from condensedProject to the full shape. It is deliberately NOT canon's hello-16 `namespace`: repository.project is condensed-project on all 127 registered pins, so a list naming the namespace would not contain the project each repository says it belongs to, and `/projects/{key}/deploy-keys` - green since the hello-15 wave on the condensed key - would answer for a key the list omits. The namespace reaches GitLab as a SUBGROUP, the surface it was modelled for. `description`, `updated_on` and `is_private` are omitted because canon says nothing about any of them", mode_reviewed: "2026-09-12", tag: "Workspaces" }
      - { method: "GET", path: "/workspaces/{workspace}/projects/{project_key}", area: "projects", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W3): the single-object twin of the list above, resolved by the key every repository publishes (the projectCtx `/projects/{key}/deploy-keys` already uses). Conformance asserts the by-key object is the listed object and that an unknown key is still Bitbucket's 404", mode_reviewed: "2026-09-12", tag: "Projects" }
      - { method: "GET", path: "/workspaces/{workspace}/projects/{project_key}/branching-model", area: "branching-model", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity BranchingModel", mode_reviewed: "2026-09-01", tag: "Branching model" }
      - { method: "GET", path: "/workspaces/{workspace}/projects/{project_key}/branching-model/settings", area: "branching-model", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity BranchingModel", mode_reviewed: "2026-09-01", tag: "Branching model" }
      - { method: "GET", path: "/workspaces/{workspace}/projects/{project_key}/default-reviewers", area: "projects", tier: 2, status: "green", mode: "empty", mode_reason: "THE PROJECT HAS NO DEFAULT REVIEWERS, because canon writes no project-scoped approval rule. hello-17 `reviewPolicy` (decisions/2026-09-11-0200) writes one approval rule per repository that has both merged pulls and an approver, and every field of it is a measurement: the approvers are the people with an `approve` review there, which is the same derivation the access pass uses to promote a plain member to repository `maintainer`, so the artifact holds ONE answer to \"who may approve here\" rather than two that can drift. Bitbucket's default reviewers are that rule read from the other end. A Bitbucket project is canon's `namespace`, the one namespace owns no repository (founder ruling F1, hello-16) and therefore has no merge to measure a policy from, so reader.listApprovalRules(\"namespace\", ns) is empty and Bitbucket's own answer is the paginated empty page at 200. READ rather than hard-coded: the query is the thing that has to say so. Falsifiable: the conformance entry asserts a REPOSITORY rule exists (so the empty is not vacuous) and that the namespace has none, and fails the day the subgroup owns a repository. Served behind the hello-17 generation gate for the reason the sibling rows state — an empty list on an older pin would be a claim about how that team reviews. RULED empty by the hello-17 bitbucket wave, 2026-09-12", mode_reviewed: "2026-09-12", tag: "Projects" }
      - { method: "GET", path: "/workspaces/{workspace}/projects/{project_key}/default-reviewers/{selected_user}", area: "projects", tier: 2, status: "deferred", mode: "generate", mode_reason: "hello-17's `reviewPolicy` IS in canon and the three REPOSITORY rows went `derive` on 2026-09-12 — but this operation addresses one reviewer of a PROJECT-scoped rule, and canon writes none: a Bitbucket project is canon's `namespace`, the one namespace owns no repository (founder ruling F1) and so has no merge to measure a policy from. The parent list is an honest empty, no `selected_user` can ever return 200, and there is nothing for conformance to validate — so the row answers the honest coverage 404 rather than being `empty` itself. THE ASK: an approval rule at namespace scope, which needs the subgroup to own a repository. Reported by the 2026-09-12 bitbucket hello-17 serving wave", mode_reviewed: "2026-09-12", tag: "Projects" }
      - { method: "GET", path: "/workspaces/{workspace}/projects/{project_key}/deploy-keys", area: "deployments", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09: the PROJECT-scoped view of the same rows — reader.listCheckoutKeys(repo) over the repositories this workspace's project holds, as `project_deploy_key` (which names its project and, unlike the repository shape, carries no `repository`). The project key is condensedProject's, the same value every repository object has advertised since Wave A, so a caller who read `project.key` off a repository can address this route with it. Answers the hello-15 generation gap on an older artifact", mode_reviewed: "2026-09-09", tag: "Deployments" }
      - { method: "GET", path: "/workspaces/{workspace}/projects/{project_key}/deploy-keys/{key_id}", area: "deployments", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09: the same project-scoped key by its numeric key_id, byte-identical to the row the project list serves. A project key this workspace does not hold is Bitbucket's own 404", mode_reviewed: "2026-09-09", tag: "Deployments" }
      - { method: "GET", path: "/workspaces/{workspace}/projects/{project_key}/permissions-config/groups", area: "projects", tier: 2, status: "green", mode: "empty", mode_reason: "NO TEAM HOLDS A GRANT ON THE WORKSPACE'S PROJECT, and this is the NARROWER reason that replaces the 2026-09-10 ruling. That ruling gave two grounds — canon binds a person to a container and never a team to one, and the project (canon's `namespace`) carries no membership row — and hello-17's `grants` makes BOTH false: a team can be a principal, and the subgroup has a roster. What is still true is where canon writes team grants: the rule measures component ownership per REPOSITORY, and the subgroup owns no repository (founder ruling F1, hello-16), so reader.teamGrants(\"namespace\", ns) is genuinely empty. Bitbucket's own answer is the paginated empty page at 200, and it is READ rather than hard-coded — the query is the thing that has to say so. Falsifiable from the side that is left: the conformance entry asserts team grants EXIST in this universe (so the empty is not vacuous) and that none of them scopes to the namespace, and fails the day one does. RULED empty by the hello-17 bitbucket wave, 2026-09-12, superseding the 2026-09-10 ruling on this row", mode_reviewed: "2026-09-12", tag: "Projects" }
      - { method: "GET", path: "/workspaces/{workspace}/projects/{project_key}/permissions-config/groups/{group_slug}", area: "projects", tier: 2, status: "deferred", mode: "generate", mode_reason: "hello-17's `grants` IS in canon and the REPOSITORY twin went `derive` on 2026-09-12 — but this operation addresses ONE group's permission on the PROJECT, and the project's group list is still empty: canon writes team-principal grants at repository scope only, because the rule measures component ownership and the subgroup owns no repository (founder ruling F1). No `group_slug` can ever return 200, so there is nothing for conformance to validate and the row answers the honest coverage 404 rather than being `empty` itself — a single-object operation has no empty collection to serve. THE ASK: a team-to-container grant at NAMESPACE scope, which needs the subgroup to own a repository. Reported by the 2026-09-12 bitbucket hello-17 serving wave", mode_reviewed: "2026-09-12", tag: "Projects" }
      - { method: "GET", path: "/workspaces/{workspace}/projects/{project_key}/permissions-config/users", area: "projects", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): the project's own roster — reader.namespaceMembers(ns), validated against `paginated_project_user_permissions`. THIS ROW WAS RULED EMPTY BY THE FOUNDER ON 2026-09-10 because the one namespace \"carries no membership row\", and that ruling named its own falsifier: the expectsEmpty entry fails \"the day a namespace gets a member\". hello-17's `grants` gives it five — the org owner, the org admins and each team's lead, the people whose authority is over the PLAN rather than over the code — which is five of seventeen, and conformance asserts the project roster is a PROPER subset of the workspace's, because a list that copied the workspace roster would make this operation indistinguishable from /workspaces/{workspace}/permissions. Bitbucket's `create-repo` rung is never produced: canon's MEMBERSHIP_PERMISSIONS has no repository-creation level at all, so emitting it would hand somebody a grant nothing in this universe made. EVERY REGISTERED PIN ANSWERS EXACTLY AS IT DID BEFORE THIS WAVE. The route carries no generation gate: it reads reader.teamGrants()/reader.namespaceMembers(), which return [] on any artifact whose canon has no such row, so a -g11 pin goes on sending the same empty page and goes on saying something true about the universe it holds. What changed is the ARGUMENT — the emptiness was called a property of the MODEL and is now a property of each ARTIFACT — and packages/conformance/src/bitbucket/access.test.ts asserts the pin answer on hello-16, hello-15 and hello-4.", mode_reviewed: "2026-09-12", tag: "Projects" }
      - { method: "GET", path: "/workspaces/{workspace}/projects/{project_key}/permissions-config/users/{selected_user_id}", area: "projects", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): one person's explicit permission on the project, addressed by the account UUID or Atlassian account id this host already resolves users by — reader.namespaceMembers(ns) narrowed to that person. THE hello-16 ASK IS ANSWERED: that wave said the row needed \"a namespace-scoped membership, the same canon the GitLab subgroup wave (#431) left open\", and hello-17's `grants` writes five. A person who is not on the subgroup's roster is Bitbucket's own 404 rather than a `permission: \"none\"` row; their workspace standing is still published by /workspaces/{workspace}/permissions, and conformance drives both. Answers the honest 404 on an artifact whose namespace has no member", mode_reviewed: "2026-09-12", tag: "Projects" }
      - { method: "GET", path: "/workspaces/{workspace}/pullrequests/{selected_user}", area: "workspaces", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W3): every pull request in the workspace one person authored - reader.listPulls() across the repositories, filtered by `pull.author`. Bitbucket's default is OPEN only and its `state` parameter is repeatable, the same grammar `/repositories/{ws}/{slug}/pullrequests` already implements and the same three words canon's states map onto. The author is addressed the way `/2.0/users/{selected_user}` addresses a person here; a member who authored nothing gets an honest empty page and a selected_user who is nobody gets Bitbucket's 404", mode_reviewed: "2026-09-12", tag: "Workspaces" }
      - { method: "GET", path: "/workspaces/{workspace}/search/code", area: "search", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (coverage wave W3): a case-insensitive substring match over the same git blobs `src` serves - the honest thing a replica holding the real files can say, and one a caller can reproduce by fetching them. Results are repository-major then path because Bitbucket ranks by relevance and this host cannot, so the same query always paginates identically. `query_substituted` is a knowable false: an unimplemented modifier is an explicit 400 rather than a silent rewrite, and only `repo:`, `project:` and `ext:` are implemented. `content_matches` carries one entry per matching LINE, with segments that reassemble the line exactly, because this host has no context window to claim around a match", mode_reviewed: "2026-09-12", tag: "Search" }
      - { method: "GET", path: "/workspaces/{workspace}/settings/gpg/public-key", area: "workspaces", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09 (hello-16): the workspace's system signing key — the `gpg` credential canon puts on the MACHINE ACCOUNT, which the entity itself explains: \"a workspace signing key is the ORG's key, not a person's, and the bot is the only principal in this universe that could hold an org-wide one\" (packages/canon/src/credentials.ts). It is therefore served HERE and excluded from /users/{selected_user}/gpg-keys, so the workspace's key is never published as somebody's own — conformance asserts both halves. The vendored swagger declares a 200 with NO content block (a documented Bitbucket spec gap), and the operation's own description — \"in most cases a single key is returned; during a key rotation period, two keys may be returned\" — describes a COLLECTION, so it is this host's ordinary paginated envelope and the shape assertion is the gate. No armored block is served, for the reason /users/{selected_user}/gpg-keys states", mode_reviewed: "2026-09-09", tag: "Workspaces" }
    graphql: [] # no GraphQL API exists for this provider (REST-only)
    git: [] # git smart-HTTP is not served for this provider yet (SPEC rev 9: GitHub first)
  ado:
    rest:
      - { method: "GET", path: "/{organization}/_apis/build/controllers", area: "build-admin", tier: 3, status: "green", mode: "empty", mode_reason: "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)", mode_reviewed: "2026-09-03", tag: "build/controllers" }
      - { method: "GET", path: "/{organization}/_apis/build/controllers/{controllerId}", area: "build-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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)", mode_reviewed: "2026-09-01", tag: "build/controllers" }
      - { method: "GET", path: "/{organization}/_apis/build/resourceusage", area: "build-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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)", mode_reviewed: "2026-09-01", tag: "build/resourceUsage" }
      - { method: "GET", path: "/{organization}/_apis/build/retention/history", area: "builds", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity RetentionLease", mode_reviewed: "2026-09-01", tag: "build/history" }
      - { method: "GET", path: "/{organization}/_apis/graph/descriptors/{storageKey}", area: "graph", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09: the reverse half of that round trip — the key /graph/storagekeys handed back returns the descriptor /graph/users published", mode_reviewed: "2026-09-09", tag: "graph/descriptors" }
      - { method: "GET", path: "/{organization}/_apis/graph/groups", area: "graph", tier: 2, status: "green", mode: "derive", tag: "graph/groups" }
      - { method: "GET", path: "/{organization}/_apis/graph/groups/{groupDescriptor}", area: "graph", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09: reader.listTeams() matched on the one-way vssgp. descriptor renderGraphGroup publishes", mode_reviewed: "2026-09-09", tag: "graph/groups" }
      - { method: "GET", path: "/{organization}/_apis/graph/Memberships/{subjectDescriptor}", area: "graph", tier: 2, status: "green", mode: "derive", tag: "graph/membershipsBatch" }
      - { method: "GET", path: "/{organization}/_apis/graph/memberships/{subjectDescriptor}/{containerDescriptor}", area: "graph", tier: 2, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "graph/memberships" }
      - { method: "HEAD", path: "/{organization}/_apis/graph/memberships/{subjectDescriptor}/{containerDescriptor}", area: "graph", tier: 2, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "graph/memberships" }
      - { method: "GET", path: "/{organization}/_apis/graph/membershipstates/{subjectDescriptor}", area: "graph", tier: 2, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "graph/membershipStates" }
      - { method: "GET", path: "/{organization}/_apis/graph/serviceprincipals", area: "graph-extras", tier: 3, status: "green", mode: "empty", mode_reason: "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.", mode_reviewed: "2026-09-12", tag: "graph/servicePrincipals" }
      - { method: "GET", path: "/{organization}/_apis/graph/serviceprincipals/{servicePrincipalDescriptor}", area: "graph-extras", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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.", mode_reviewed: "2026-09-12", tag: "graph/servicePrincipals" }
      - { method: "GET", path: "/{organization}/_apis/graph/storagekeys/{subjectDescriptor}", area: "graph-extras", tier: 3, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "graph/storageKeys" }
      - { method: "GET", path: "/{organization}/_apis/graph/Subjects/{subjectDescriptor}/avatars", area: "graph-extras", tier: 3, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-03", tag: "graph/avatars" }
      - { method: "GET", path: "/{organization}/_apis/graph/users", area: "graph", tier: 2, status: "green", mode: "derive", tag: "graph/users" }
      - { method: "GET", path: "/{organization}/_apis/graph/users/{userDescriptor}", area: "graph", tier: 2, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "graph/users" }
      - { method: "GET", path: "/{organization}/_apis/graph/Users/{userDescriptor}/providerinfo", area: "graph-extras", tier: 3, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-12", tag: "graph/providerInfo" }
      - { method: "GET", path: "/{organization}/_apis/identities", area: "identities", tier: 2, status: "green", mode: "derive", tag: "ims/identities" }
      - { method: "GET", path: "/{organization}/_apis/process/processes", area: "core-admin", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "core/processes" }
      - { method: "GET", path: "/{organization}/_apis/process/processes/{processId}", area: "core-admin", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "core/processes" }
      - { method: "GET", path: "/{organization}/_apis/projects", area: "core", tier: 1, status: "green", mode: "derive", tag: "core/projects" }
      - { method: "GET", path: "/{organization}/_apis/projects/{projectId}", area: "core", tier: 1, status: "green", mode: "derive", tag: "core/projects" }
      - { method: "GET", path: "/{organization}/_apis/projects/{projectId}/categorizedteams/", area: "core-admin", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "core/categorizedTeams" }
      - { method: "GET", path: "/{organization}/_apis/projects/{projectId}/properties", area: "core-admin", tier: 3, status: "green", mode: "empty", mode_reason: "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.", mode_reviewed: "2026-09-12", tag: "core/properties" }
      - { method: "GET", path: "/{organization}/_apis/projects/{projectId}/teams", area: "core", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09: the project-scoped form of the same reader.listTeams() list, guarded on the project", mode_reviewed: "2026-09-09", tag: "core/teams" }
      - { method: "GET", path: "/{organization}/_apis/projects/{projectId}/teams/{teamId}", area: "core", tier: 1, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "core/teams" }
      - { method: "GET", path: "/{organization}/_apis/projects/{projectId}/teams/{teamId}/members", area: "core", tier: 1, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-10", tag: "core/members" }
      - { method: "GET", path: "/{organization}/_apis/public/build/definitions/{project}/{definitionId}/badge", area: "build-admin", tier: 3, status: "green", mode: "derive", mode_reason: "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)", mode_reviewed: "2026-09-03", tag: "build/badge" }
      - { method: "GET", path: "/{organization}/_apis/teams", area: "core", tier: 1, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "core/teams" }
      - { method: "GET", path: "/{organization}/_apis/wit/artifactlinktypes", area: "wit-metadata", tier: 3, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "wit/artifactLinkTypes" }
      - { method: "GET", path: "/{organization}/_apis/wit/workitemicons", area: "wit-metadata", tier: 3, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "wit/workItemIcons" }
      - { method: "GET", path: "/{organization}/_apis/wit/workitemicons/{icon}", area: "wit-metadata", tier: 3, status: "green", mode: "derive", mode_reason: "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)", mode_reviewed: "2026-09-03", tag: "wit/workItemIcons" }
      - { method: "GET", path: "/{organization}/_apis/wit/workitemrelationtypes", area: "wit-metadata", tier: 2, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "wit/workItemRelationTypes" }
      - { method: "GET", path: "/{organization}/_apis/wit/workitemrelationtypes/{relation}", area: "wit-metadata", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09: the single read off that same table, by reference name or friendly name", mode_reviewed: "2026-09-09", tag: "wit/workItemRelationTypes" }
      - { method: "GET", path: "/{organization}/_apis/wit/workitemtransitions", area: "wit-metadata", tier: 2, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "wit/workItemTransitions" }
      - { method: "GET", path: "/{organization}/_apis/work/accountmyworkrecentactivity", area: "work-item-extras", tier: 3, status: "green", mode: "empty", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "wit/accountMyWorkRecentActivity" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/authorizedresources", area: "build-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsPolicy", mode_reviewed: "2026-09-01", tag: "build/authorizedresources" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/builds", area: "builds", tier: 1, status: "green", mode: "derive", tag: "build/builds" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/builds/{buildId}", area: "builds", tier: 1, status: "green", mode: "derive", tag: "build/builds" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/builds/{buildId}/{timelineId}/{recordId}/attachments/{type}/{name}", area: "build-admin", tier: 3, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "build/attachments" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/builds/{buildId}/artifacts", area: "builds", tier: 1, status: "green", mode: "derive", tag: "build/artifacts" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/builds/{buildId}/artifacts?artifactName={artifactName}", area: "builds", tier: 1, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "build/artifacts" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/builds/{buildId}/artifacts?artifactName={artifactName}&fileId={fileId}&fileName={fileName}", area: "builds", tier: 1, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "build/artifacts" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/builds/{buildId}/attachments/{type}", area: "build-admin", tier: 3, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "build/attachments" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/builds/{buildId}/changes", area: "builds", tier: 1, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "build/changes" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/builds/{buildId}/leases", area: "build-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity RetentionLease", mode_reviewed: "2026-09-01", tag: "build/buildleases" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/builds/{buildId}/logs", area: "builds", tier: 2, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-02", tag: "build/logs" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/builds/{buildId}/logs/{logId}", area: "builds", tier: 2, status: "green", mode: "derive", mode_reason: "the log content itself - reader.jobLogText(job) as text/plain, sliced by the operation's own startLine/endLine", mode_reviewed: "2026-09-02", tag: "build/logs" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/builds/{buildId}/properties", area: "build-admin", tier: 3, status: "green", mode: "empty", mode_reason: "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.", mode_reviewed: "2026-09-12", tag: "build/properties" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/builds/{buildId}/report", area: "builds", tier: 2, status: "deferred", mode: "refuse", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "build/report" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/builds/{buildId}/tags", area: "builds", tier: 2, status: "green", mode: "empty", mode_reason: "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.", mode_reviewed: "2026-09-12", tag: "build/tags" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/builds/{buildId}/timeline/{timelineId}", area: "builds", tier: 1, status: "green", mode: "derive", tag: "build/timeline" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/builds/{buildId}/workitems", area: "builds", tier: 2, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "build/workitems" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/changes", area: "builds", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09: the fromBuildId..toBuildId range form of the same reader.commitsOnlyIn arithmetic", mode_reviewed: "2026-09-09", tag: "build/changes" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/definitions", area: "builds", tier: 1, status: "green", mode: "derive", tag: "build/definitions" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/definitions/{definitionId}", area: "builds", tier: 1, status: "green", mode: "derive", tag: "build/definitions" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/definitions/{definitionId}/metrics", area: "builds", tier: 2, status: "deferred", mode: "refuse", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "build/metrics" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/definitions/{definitionId}/properties", area: "build-admin", tier: 3, status: "green", mode: "empty", mode_reason: "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.", mode_reviewed: "2026-09-12", tag: "build/properties" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/definitions/{definitionId}/resources", area: "build-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsPolicy", mode_reviewed: "2026-09-01", tag: "build/resources" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/definitions/{definitionId}/revisions", area: "builds", tier: 2, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "build/revisions" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/definitions/{DefinitionId}/tags", area: "builds", tier: 2, status: "green", mode: "empty", mode_reason: "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.", mode_reviewed: "2026-09-12", tag: "build/tags" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/definitions/{definitionId}/yaml", area: "build-admin", tier: 3, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-12", tag: "build/yaml" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/definitions/templates", area: "build-admin", tier: 3, status: "deferred", mode: "derive", mode_reviewed: "2026-09-01", tag: "build/templates" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/definitions/templates/{templateId}", area: "build-admin", tier: 3, status: "deferred", mode: "derive", mode_reviewed: "2026-09-01", tag: "build/templates" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/folders/{path}", area: "build-admin", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "build/folders" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/generalsettings", area: "build-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsPolicy", mode_reviewed: "2026-09-01", tag: "build/generalSettings" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/latest/{definition}", area: "builds", tier: 1, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "build/latest" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/metrics/{metricAggregationType}", area: "builds", tier: 2, status: "deferred", mode: "refuse", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "build/metrics" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/options", area: "build-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsPolicy", mode_reviewed: "2026-09-01", tag: "build/options" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/repos/{repoType}/badge", area: "build-admin", tier: 3, status: "green", mode: "derive", mode_reason: "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)", mode_reviewed: "2026-09-03", tag: "build/buildbadge" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/retention", area: "build-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsPolicy", mode_reviewed: "2026-09-01", tag: "build/retention" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/retention/leases", area: "build-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity RetentionLease", mode_reviewed: "2026-09-01", tag: "build/leases" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/retention/leases?", area: "build-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity RetentionLease", mode_reviewed: "2026-09-01", tag: "build/leases" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/retention/leases?userOwnerId={userOwnerId}", area: "build-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity RetentionLease", mode_reviewed: "2026-09-01", tag: "build/leases" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/retention/leases/{leaseId}", area: "build-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity RetentionLease", mode_reviewed: "2026-09-01", tag: "build/leases" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/settings", area: "build-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity ActionsPolicy", mode_reviewed: "2026-09-01", tag: "build/settings" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/status/{definition}", area: "builds", tier: 2, status: "green", mode: "derive", mode_reason: "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)", mode_reviewed: "2026-09-03", tag: "build/status" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/tags", area: "builds", tier: 2, status: "green", mode: "empty", mode_reason: "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.", mode_reviewed: "2026-09-12", tag: "build/tags" }
      - { method: "GET", path: "/{organization}/{project}/_apis/build/workitems", area: "builds", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09: the fromBuildId..toBuildId range form of the same reader.pullsForCommit walk", mode_reviewed: "2026-09-09", tag: "build/workitems" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/deletedrepositories", area: "git-admin", tier: 3, status: "green", mode: "empty", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "git/deletedRepositories" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/favorites/refs", area: "git-admin", tier: 3, status: "green", mode: "empty", mode_reason: "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.", mode_reviewed: "2026-09-12", tag: "git/refsFavorites" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/favorites/refs/{favoriteId}", area: "git-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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.", mode_reviewed: "2026-09-12", tag: "git/refsFavorites" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/policy/configurations", area: "policy", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity BranchRestriction", mode_reviewed: "2026-09-01", tag: "git/policyConfigurations" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/pullrequests", area: "pulls", tier: 1, status: "green", mode: "derive", tag: "git/pullRequests" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/pullrequests/{pullRequestId}", area: "pulls", tier: 1, status: "green", mode: "derive", tag: "git/pullRequests" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/recycleBin/repositories", area: "git-admin", tier: 3, status: "green", mode: "empty", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "git/recycleBinRepositories" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories", area: "git", tier: 1, status: "green", mode: "derive", tag: "git/repositories" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}", area: "git", tier: 1, status: "green", mode: "derive", tag: "git/repositories" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}?includeParent={includeParent}", area: "git", tier: 1, status: "green", mode: "derive", tag: "git/repositories" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/annotatedtags/{objectId}", area: "git", tier: 2, status: "deferred", mode: "refuse", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "git/annotatedTags" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/blobs/{sha1}", area: "git-content", tier: 1, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "git/blobs" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/cherryPicks", area: "git-write-adjacent", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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)", mode_reviewed: "2026-09-01", tag: "git/cherryPicks" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/cherryPicks/{cherryPickId}", area: "git-write-adjacent", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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)", mode_reviewed: "2026-09-01", tag: "git/cherryPicks" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/commits", area: "git", tier: 1, status: "green", mode: "derive", tag: "git/commits" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/commits?", area: "git", tier: 1, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "git/commits" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/commits/{commitId}", area: "git", tier: 1, status: "green", mode: "derive", tag: "git/commits" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/commits/{commitId}/changes", area: "git", tier: 1, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "git/changes" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/commits/{commitId}/statuses", area: "commit-statuses", tier: 1, status: "green", mode: "derive", tag: "git/statuses" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/diffs/commits", area: "git", tier: 1, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "git/commitDiffs" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/importRequests", area: "git-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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)", mode_reviewed: "2026-09-01", tag: "git/importRequests" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/importRequests/{importRequestId}", area: "git-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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)", mode_reviewed: "2026-09-01", tag: "git/importRequests" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/items", area: "git-content", tier: 1, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "git/items" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/items?path={path}", area: "git-content", tier: 1, status: "green", mode: "derive", mode_reason: "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)", mode_reviewed: "2026-09-09", tag: "git/items" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/pullrequests", area: "pulls", tier: 1, status: "green", mode: "derive", tag: "git/pullRequests" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/pullrequests/{pullRequestId}", area: "pulls", tier: 1, status: "green", mode: "derive", tag: "git/pullRequests" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/pullRequests/{pullRequestId}/attachments", area: "pulls-extras", tier: 3, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-12", tag: "git/pullRequestAttachments" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/pullRequests/{pullRequestId}/attachments/{fileName}", area: "pulls-extras", tier: 3, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-12", tag: "git/pullRequestAttachments" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/pullRequests/{pullRequestId}/commits", area: "pulls", tier: 1, status: "green", mode: "derive", tag: "git/pullRequestCommits" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/pullRequests/{pullRequestId}/iterations", area: "pulls", tier: 1, status: "green", mode: "derive", tag: "git/pullRequestIterations" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/pullRequests/{pullRequestId}/iterations/{iterationId}", area: "pulls", tier: 1, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "git/pullRequestIterations" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/pullRequests/{pullRequestId}/iterations/{iterationId}/changes", area: "pulls", tier: 1, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "git/pullRequestIterationChanges" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/pullRequests/{pullRequestId}/iterations/{iterationId}/commits", area: "pulls", tier: 1, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "git/pullRequestCommits" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/pullRequests/{pullRequestId}/iterations/{iterationId}/statuses", area: "pulls", tier: 2, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "git/pullRequestIterationStatuses" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/pullRequests/{pullRequestId}/iterations/{iterationId}/statuses/{statusId}", area: "pulls", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09: the single read off the same reader.checksForCommit list the iteration's statuses route serves", mode_reviewed: "2026-09-09", tag: "git/pullRequestIterationStatuses" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/pullRequests/{pullRequestId}/labels", area: "pulls", tier: 1, status: "green", mode: "derive", tag: "git/pullRequestLabels" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/pullRequests/{pullRequestId}/labels/{labelIdOrName}", area: "pulls", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09: reader.pullLabels(pull), addressed by either half of {labelIdOrName} — the deterministic label guid or the canonical label name", mode_reviewed: "2026-09-09", tag: "git/pullRequestLabels" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/pullRequests/{pullRequestId}/properties", area: "pulls-extras", tier: 3, status: "green", mode: "empty", mode_reason: "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.", mode_reviewed: "2026-09-12", tag: "git/pullRequestProperties" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/pullRequests/{pullRequestId}/reviewers", area: "pulls", tier: 1, status: "green", mode: "derive", tag: "git/pullRequestReviewers" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/pullRequests/{pullRequestId}/reviewers/{reviewerId}", area: "pulls", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09: reader.listReviews + reader.pullRequestedReviewers, addressed by the identity guid the reviewers list publishes in each row's reviewerUrl", mode_reviewed: "2026-09-09", tag: "git/pullRequestReviewers" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/pullRequests/{pullRequestId}/statuses", area: "pulls", tier: 1, status: "green", mode: "derive", tag: "git/pullRequestStatuses" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/pullRequests/{pullRequestId}/statuses/{statusId}", area: "pulls", tier: 1, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "git/pullRequestStatuses" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/pullRequests/{pullRequestId}/threads", area: "pulls", tier: 1, status: "green", mode: "derive", tag: "git/pullRequestThreads" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/pullRequests/{pullRequestId}/threads/{threadId}", area: "pulls", tier: 1, status: "green", mode: "derive", tag: "git/pullRequestThreads" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/pullRequests/{pullRequestId}/threads/{threadId}/comments", area: "pulls", tier: 1, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "git/pullRequestThreadComments" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/pullRequests/{pullRequestId}/threads/{threadId}/comments/{commentId}", area: "pulls", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09: the single read off that same thread document", mode_reviewed: "2026-09-09", tag: "git/pullRequestThreadComments" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/pullRequests/{pullRequestId}/threads/{threadId}/comments/{commentId}/likes", area: "pulls-extras", tier: 3, status: "deferred", mode: "generate", mode_reason: "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", mode_reviewed: "2026-09-07", tag: "git/pullRequestCommentLikes" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/pullRequests/{pullRequestId}/workitems", area: "pulls", tier: 1, status: "green", mode: "derive", tag: "git/pullRequestWorkItems" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/pushes", area: "git", tier: 1, status: "green", mode: "derive", tag: "git/pushes" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/pushes/{pushId}", area: "git", tier: 1, status: "green", mode: "derive", tag: "git/pushes" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/refs", area: "git", tier: 1, status: "green", mode: "derive", tag: "git/refs" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/reverts", area: "git-write-adjacent", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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)", mode_reviewed: "2026-09-01", tag: "git/reverts" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/reverts/{revertId}", area: "git-write-adjacent", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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)", mode_reviewed: "2026-09-01", tag: "git/reverts" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/stats/branches", area: "git", tier: 1, status: "green", mode: "derive", tag: "git/branchStats" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/stats/branches?name={name}", area: "git", tier: 1, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "git/branchStats" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/suggestions", area: "pulls", tier: 2, status: "green", mode: "empty", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "git/suggestions" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryId}/trees/{sha1}", area: "git-content", tier: 1, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "git/trees" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryNameOrId}/commits/{commitId}/mergebases", area: "git", tier: 2, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "git/mergeBases" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryNameOrId}/forks/{collectionId}", area: "git", tier: 2, status: "green", mode: "empty", mode_reason: "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", mode_reviewed: "2026-09-01", tag: "git/forks" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryNameOrId}/forkSyncRequests", area: "git", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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)", mode_reviewed: "2026-09-01", tag: "git/forkSyncRequests" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryNameOrId}/forkSyncRequests/{forkSyncOperationId}", area: "git", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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)", mode_reviewed: "2026-09-01", tag: "git/forkSyncRequests" }
      - { method: "GET", path: "/{organization}/{project}/_apis/git/repositories/{repositoryNameOrId}/merges/{mergeOperationId}", area: "git-write-adjacent", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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)", mode_reviewed: "2026-09-01", tag: "git/merges" }
      - { method: "GET", path: "/{organization}/{project}/_apis/pipelines", area: "pipelines", tier: 1, status: "green", mode: "derive", tag: "pipelines/pipelines" }
      - { method: "GET", path: "/{organization}/{project}/_apis/pipelines/{pipelineId}", area: "pipelines", tier: 1, status: "green", mode: "derive", tag: "pipelines/pipelines" }
      - { method: "GET", path: "/{organization}/{project}/_apis/pipelines/{pipelineId}/runs", area: "pipelines", tier: 1, status: "green", mode: "derive", tag: "pipelines/runs" }
      - { method: "GET", path: "/{organization}/{project}/_apis/pipelines/{pipelineId}/runs/{runId}", area: "pipelines", tier: 1, status: "green", mode: "derive", tag: "pipelines/runs" }
      - { method: "GET", path: "/{organization}/{project}/_apis/pipelines/{pipelineId}/runs/{runId}/artifacts", area: "pipelines", tier: 2, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "pipelines/artifacts" }
      - { method: "GET", path: "/{organization}/{project}/_apis/pipelines/{pipelineId}/runs/{runId}/logs", area: "pipelines", tier: 2, status: "green", mode: "derive", mode_reason: "the pipelines-surface twin of the build log list: a LogCollection over the same canonical job logs", mode_reviewed: "2026-09-02", tag: "pipelines/logs" }
      - { method: "GET", path: "/{organization}/{project}/_apis/pipelines/{pipelineId}/runs/{runId}/logs/{logId}", area: "pipelines", tier: 2, status: "green", mode: "derive", mode_reason: "the pipelines-surface Log metadata for one canonical job log; signedContent is refused rather than invented, this universe runs no signed blob store", mode_reviewed: "2026-09-02", tag: "pipelines/logs" }
      - { method: "GET", path: "/{organization}/{project}/_apis/sourceproviders", area: "build-admin", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "build/sourceProviders" }
      - { method: "GET", path: "/{organization}/{project}/_apis/sourceProviders/{providerName}/branches", area: "builds", tier: 2, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "build/branches" }
      - { method: "GET", path: "/{organization}/{project}/_apis/sourceProviders/{providerName}/filecontents", area: "build-admin", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "build/fileContents" }
      - { method: "GET", path: "/{organization}/{project}/_apis/sourceProviders/{providerName}/pathcontents", area: "build-admin", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "build/pathContents" }
      - { method: "GET", path: "/{organization}/{project}/_apis/sourceProviders/{providerName}/pullrequests/{pullRequestId}", area: "builds", tier: 2, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "build/pullRequests" }
      - { method: "GET", path: "/{organization}/{project}/_apis/sourceProviders/{providerName}/repositories", area: "build-admin", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "build/repositories" }
      - { method: "GET", path: "/{organization}/{project}/_apis/sourceProviders/{providerName}/webhooks", area: "build-admin", tier: 3, status: "green", mode: "empty", mode_reason: "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.", mode_reviewed: "2026-09-12", tag: "build/webhooks" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/attachments/{id}", area: "attachments", tier: 2, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-12", tag: "wit/attachments" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/classificationnodes", area: "wit-metadata", tier: 1, status: "green", mode: "derive", tag: "wit/classificationNodes" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/classificationnodes?ids={ids}", area: "wit-metadata", tier: 1, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "wit/classificationNodes" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/classificationnodes/{structureGroup}/{path}", area: "wit-metadata", tier: 1, status: "green", mode: "derive", tag: "wit/classificationNodes" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/fields", area: "wit-metadata", tier: 1, status: "green", mode: "derive", tag: "wit/fields" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/fields/{fieldNameOrRefName}", area: "wit-metadata", tier: 1, status: "green", mode: "derive", tag: "wit/fields" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/queries", area: "queries", tier: 2, status: "green", mode: "derive", mode_reason: "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)", mode_reviewed: "2026-09-12", tag: "wit/queries" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/queries?$filter={$filter}", area: "queries", tier: 2, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-12", tag: "wit/queries" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/queries/{query}", area: "queries", tier: 2, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-12", tag: "wit/queries" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/recyclebin", area: "wit-admin", tier: 3, status: "green", mode: "derive", mode_reason: "hello-13's DeletedWorkItem canon: two work items were filed and then deleted, so the bin lists their shallow references", mode_reviewed: "2026-09-02", tag: "wit/recyclebin" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/recyclebin?ids={ids}", area: "wit-admin", tier: 3, status: "green", mode: "derive", mode_reason: "the by-ids variant of the same bin, serving the fuller WorkItemDeleteReference for each requested id", mode_reviewed: "2026-09-02", tag: "wit/recyclebin" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/recyclebin/{id}", area: "wit-admin", tier: 3, status: "green", mode: "derive", mode_reason: "the single deleted work item, resource and all, from the same canon row; an id nobody deleted is an ordinary 404", mode_reviewed: "2026-09-02", tag: "wit/recyclebin" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/reporting/workitemlinks", area: "reporting", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "wit/workItemLinks" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/reporting/workitemrevisions", area: "reporting", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "wit/workItemRevisions" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/reporting/workItemRevisions/discussions", area: "reporting", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "wit/workItemRevisionsDiscussions" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/tags", area: "wit-metadata", tier: 2, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "wit/tags" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/tags/{tagIdOrName}", area: "wit-metadata", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09: the single read off that same list, by deterministic tag guid or by name", mode_reviewed: "2026-09-09", tag: "wit/tags" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/workitems", area: "work-items", tier: 1, status: "green", mode: "derive", tag: "wit/workItems" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/workitems/{id}", area: "work-items", tier: 1, status: "green", mode: "derive", tag: "wit/workItems" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/workItems/{id}/revisions", area: "work-items", tier: 1, status: "green", mode: "derive", tag: "wit/revisions" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/workItems/{id}/revisions/{revisionNumber}", area: "work-items", tier: 1, status: "green", mode: "derive", tag: "wit/revisions" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/workItems/{id}/updates", area: "work-items", tier: 1, status: "green", mode: "derive", tag: "wit/updates" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/workItems/{id}/updates/{updateNumber}", area: "work-items", tier: 1, status: "green", mode: "derive", tag: "wit/updates" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/workItems/{workItemId}/comments", area: "work-items", tier: 1, status: "green", mode: "derive", tag: "wit/comments" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/workItems/{workItemId}/comments?", area: "work-items", tier: 1, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "wit/comments" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/workItems/{workItemId}/comments/{commentId}", area: "work-items", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09: the single read off the same renderComments() document, found by the id that list published", mode_reviewed: "2026-09-09", tag: "wit/comments" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/workItems/{workItemId}/comments/{commentId}/reactions", area: "work-item-extras", tier: 3, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-07", tag: "wit/commentsReactions" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/workItems/{workItemId}/comments/{commentId}/reactions/{reactionType}/users", area: "work-item-extras", tier: 3, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-07", tag: "wit/commentReactionsEngagedUsers" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/workItems/{workItemId}/comments/{commentId}/versions", area: "work-items", tier: 2, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "wit/commentsVersions" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/workItems/{workItemId}/comments/{commentId}/versions/{version}", area: "work-items", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09: the single read off that one-entry history", mode_reviewed: "2026-09-09", tag: "wit/commentsVersions" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/workitems/${type}", area: "work-items", tier: 1, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "wit/workItems" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/workitemtypecategories", area: "wit-metadata", tier: 2, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "wit/workItemTypeCategories" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/workitemtypecategories/{category}", area: "wit-metadata", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09: the single read off that same table", mode_reviewed: "2026-09-09", tag: "wit/workItemTypeCategories" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/workitemtypes", area: "wit-metadata", tier: 1, status: "green", mode: "derive", tag: "wit/workItemTypes" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/workitemtypes/{type}", area: "wit-metadata", tier: 1, status: "green", mode: "derive", tag: "wit/workItemTypes" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/workitemtypes/{type}/fields", area: "wit-metadata", tier: 2, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-10", tag: "wit/workItemTypesField" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/workitemtypes/{type}/fields/{field}", area: "wit-metadata", tier: 2, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-10", tag: "wit/workItemTypesField" }
      - { method: "GET", path: "/{organization}/{project}/_apis/wit/workitemtypes/{type}/states", area: "wit-metadata", tier: 1, status: "green", mode: "derive", tag: "wit/workItemTypeStates" }
      - { method: "GET", path: "/{organization}/{project}/_apis/work/boardcolumns", area: "boards", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09: the column names renderBoard() really puts on this project's boards, as BoardSuggestedValue", mode_reviewed: "2026-09-09", tag: "work/boardcolumns" }
      - { method: "GET", path: "/{organization}/{project}/_apis/work/boardrows", area: "boards", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09: the swimlane names renderBoard() really puts on this project's boards", mode_reviewed: "2026-09-09", tag: "work/boardrows" }
      - { method: "GET", path: "/{organization}/{project}/_apis/work/iterations/{iterationId}/iterationcapacities", area: "iterations", tier: 2, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "work/iterationcapacities" }
      - { method: "GET", path: "/{organization}/{project}/_apis/work/plans", area: "plans", tier: 3, status: "green", mode: "empty", mode_reason: "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.", mode_reviewed: "2026-09-12", tag: "work/plans" }
      - { method: "GET", path: "/{organization}/{project}/_apis/work/plans/{id}", area: "plans", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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.", mode_reviewed: "2026-09-12", tag: "work/plans" }
      - { method: "GET", path: "/{organization}/{project}/_apis/work/plans/{id}/deliverytimeline", area: "plans", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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.", mode_reviewed: "2026-09-12", tag: "work/deliverytimeline" }
      - { method: "GET", path: "/{organization}/{project}/_apis/work/processconfiguration", area: "team-settings", tier: 3, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "work/processconfiguration" }
      - { method: "GET", path: "/{organization}/{project}/{team}/_apis/wit/templates", area: "wit-admin", tier: 3, status: "green", mode: "empty", mode_reason: "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.", mode_reviewed: "2026-09-12", tag: "wit/templates" }
      - { method: "GET", path: "/{organization}/{project}/{team}/_apis/wit/templates/{templateId}", area: "wit-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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.", mode_reviewed: "2026-09-12", tag: "wit/templates" }
      - { method: "GET", path: "/{organization}/{project}/{team}/_apis/wit/wiql/{id}", area: "wiql", tier: 1, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-12", tag: "wit/wiql" }
      - { method: "HEAD", path: "/{organization}/{project}/{team}/_apis/wit/wiql/{id}", area: "wiql", tier: 1, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-12", tag: "wit/wiql" }
      - { method: "GET", path: "/{organization}/{project}/{team}/_apis/work/backlogconfiguration", area: "backlogs", tier: 2, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "work/backlogconfiguration" }
      - { method: "GET", path: "/{organization}/{project}/{team}/_apis/work/backlogs", area: "backlogs", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09: the Requirement and Task levels, each naming only work-item types /wit/workitemtypes returns", mode_reviewed: "2026-09-09", tag: "work/backlogs" }
      - { method: "GET", path: "/{organization}/{project}/{team}/_apis/work/backlogs/{backlogId}/workItems", area: "backlogs", tier: 2, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "work/backlogs" }
      - { method: "GET", path: "/{organization}/{project}/{team}/_apis/work/backlogs/{id}", area: "backlogs", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09: the single read off that same list, by category reference name or level name", mode_reviewed: "2026-09-09", tag: "work/backlogs" }
      - { method: "GET", path: "/{organization}/{project}/{team}/_apis/work/boards", area: "boards", tier: 1, status: "green", mode: "derive", tag: "work/boards" }
      - { method: "GET", path: "/{organization}/{project}/{team}/_apis/work/boards/{board}/boardusersettings", area: "boards", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity BoardConfig", mode_reviewed: "2026-09-01", tag: "work/boardusersettings" }
      - { method: "GET", path: "/{organization}/{project}/{team}/_apis/work/boards/{board}/cardrulesettings", area: "board-viz", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity BoardConfig", mode_reviewed: "2026-09-01", tag: "work/cardrulesettings" }
      - { method: "GET", path: "/{organization}/{project}/{team}/_apis/work/boards/{board}/cardsettings", area: "board-viz", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity BoardConfig", mode_reviewed: "2026-09-01", tag: "work/cardsettings" }
      - { method: "GET", path: "/{organization}/{project}/{team}/_apis/work/boards/{board}/chartimages/{name}", area: "board-viz", tier: 3, status: "deferred", mode: "derive", mode_reason: "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)", mode_reviewed: "2026-09-03", tag: "work/chartimages" }
      - { method: "GET", path: "/{organization}/{project}/{team}/_apis/work/boards/{board}/charts", area: "board-viz", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-01", tag: "work/charts" }
      - { method: "GET", path: "/{organization}/{project}/{team}/_apis/work/boards/{board}/charts/{name}", area: "board-viz", tier: 3, status: "deferred", mode: "derive", mode_reviewed: "2026-09-01", tag: "work/charts" }
      - { method: "GET", path: "/{organization}/{project}/{team}/_apis/work/boards/{board}/columns", area: "boards", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09: the same four columns renderBoard() embeds in the board document, so the board and this list cannot describe different columns", mode_reviewed: "2026-09-09", tag: "work/columns" }
      - { method: "GET", path: "/{organization}/{project}/{team}/_apis/work/boards/{board}/rows", area: "boards", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09: the same swimlane renderBoard() embeds", mode_reviewed: "2026-09-09", tag: "work/rows" }
      - { method: "GET", path: "/{organization}/{project}/{team}/_apis/work/boards/{id}", area: "boards", tier: 1, status: "green", mode: "derive", tag: "work/boards" }
      - { method: "GET", path: "/{organization}/{project}/{team}/_apis/work/boards/boardparents", area: "boards", tier: 3, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-10", tag: "work/boardparents" }
      - { method: "GET", path: "/{organization}/{project}/{team}/_apis/work/iterations/{iterationId}/chartimages/{name}", area: "board-viz", tier: 3, status: "deferred", mode: "derive", mode_reason: "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)", mode_reviewed: "2026-09-03", tag: "work/chartimages" }
      - { method: "GET", path: "/{organization}/{project}/{team}/_apis/work/iterations/chartimages/{name}", area: "board-viz", tier: 3, status: "deferred", mode: "derive", mode_reason: "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)", mode_reviewed: "2026-09-03", tag: "work/chartimages" }
      - { method: "GET", path: "/{organization}/{project}/{team}/_apis/work/taskboardcolumns", area: "taskboard", tier: 3, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "work/taskboardColumns" }
      - { method: "GET", path: "/{organization}/{project}/{team}/_apis/work/taskboardworkitems/{iterationId}", area: "taskboard", tier: 3, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "work/taskboardWorkItems" }
      - { method: "GET", path: "/{organization}/{project}/{team}/_apis/work/teamsettings", area: "team-settings", tier: 2, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-12", tag: "work/teamsettings" }
      - { method: "GET", path: "/{organization}/{project}/{team}/_apis/work/teamsettings/iterations", area: "iterations", tier: 1, status: "green", mode: "derive", tag: "work/iterations" }
      - { method: "GET", path: "/{organization}/{project}/{team}/_apis/work/teamsettings/iterations/{id}", area: "iterations", tier: 1, status: "green", mode: "derive", tag: "work/iterations" }
      - { method: "GET", path: "/{organization}/{project}/{team}/_apis/work/teamsettings/iterations/{iterationId}/capacities", area: "iterations", tier: 1, status: "green", mode: "derive", tag: "work/capacities" }
      - { method: "GET", path: "/{organization}/{project}/{team}/_apis/work/teamsettings/iterations/{iterationId}/capacities/{teamMemberId}", area: "iterations", tier: 1, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-09", tag: "work/capacities" }
      - { method: "GET", path: "/{organization}/{project}/{team}/_apis/work/teamsettings/iterations/{iterationId}/teamdaysoff", area: "iterations", tier: 3, status: "green", mode: "empty", mode_reason: "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.", mode_reviewed: "2026-09-12", tag: "work/teamdaysoff" }
      - { method: "GET", path: "/{organization}/{project}/{team}/_apis/work/teamsettings/iterations/{iterationId}/workitems", area: "boards", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09: the team's tracker issues in that sprint, as the target-only WorkItemLink rows a flat listing uses", mode_reviewed: "2026-09-09", tag: "work/workitems" }
      - { method: "GET", path: "/{organization}/{project}/{team}/_apis/work/teamsettings/teamfieldvalues", area: "team-settings", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-09: a team owns its own area path, which is the same System.AreaPath every one of its work items carries", mode_reviewed: "2026-09-09", tag: "work/teamfieldvalues" }
    graphql: [] # no GraphQL API exists for this provider (REST-only)
    git: [] # git smart-HTTP is not served for this provider yet (SPEC rev 9: GitHub first)
  jira:
    rest:
      - { method: "GET", path: "/rest/agile/1.0/board", area: "boards", tier: 1, status: "green", mode: "derive", tag: "software/Board" }
      - { method: "GET", path: "/rest/agile/1.0/board/{boardId}", area: "boards", tier: 1, status: "green", mode: "derive", tag: "software/Board" }
      - { method: "GET", path: "/rest/agile/1.0/board/{boardId}/backlog", area: "boards", tier: 1, status: "green", mode: "derive", tag: "software/Board" }
      - { method: "GET", path: "/rest/agile/1.0/board/{boardId}/configuration", area: "boards", tier: 1, status: "planned", mode: "generate", mode_reason: "new canon entity BoardConfig", mode_reviewed: "2026-09-01", tag: "software/Board" }
      - { method: "GET", path: "/rest/agile/1.0/board/{boardId}/epic", area: "boards", tier: 1, status: "green", mode: "derive", tag: "software/Board" }
      - { method: "GET", path: "/rest/agile/1.0/board/{boardId}/epic/{epicId}/issue", area: "boards", tier: 1, status: "green", mode: "derive", tag: "software/Board" }
      - { method: "GET", path: "/rest/agile/1.0/board/{boardId}/epic/none/issue", area: "boards", tier: 1, status: "green", mode: "derive", tag: "software/Board" }
      - { method: "GET", path: "/rest/agile/1.0/board/{boardId}/features", area: "boards", tier: 1, status: "planned", mode: "generate", mode_reason: "new canon entity BoardConfig", mode_reviewed: "2026-09-01", tag: "software/Board" }
      - { method: "GET", path: "/rest/agile/1.0/board/{boardId}/issue", area: "boards", tier: 1, status: "green", mode: "derive", tag: "software/Board" }
      - { method: "GET", path: "/rest/agile/1.0/board/{boardId}/project", area: "boards", tier: 1, status: "green", mode: "derive", tag: "software/Board" }
      - { method: "GET", path: "/rest/agile/1.0/board/{boardId}/project/full", area: "boards", tier: 1, status: "green", mode: "derive", mode_reason: "the team table the renderer already renders as projects", mode_reviewed: "2026-09-01", tag: "software/Board" }
      - { method: "GET", path: "/rest/agile/1.0/board/{boardId}/properties", area: "boards", tier: 1, status: "green", mode: "empty", mode_reason: "no entity in this Jira site carries an app property - entity properties are written only by Connect/Forge apps through the API and olympus-labs installs none, and this universe accepts no writes; Jira's own answer for a property key that is not set is 404 \"The property key was not found\", and its answer for an entity that carries none is the empty `{\"keys\": []}` this operation declares. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "software/Board" }
      - { method: "GET", path: "/rest/agile/1.0/board/{boardId}/properties/{propertyKey}", area: "boards", tier: 1, status: "planned", mode: "refuse", mode_reason: "no entity in this Jira site carries an app property - entity properties are written only by Connect/Forge apps through the API and olympus-labs installs none, and this universe accepts no writes; Jira's own answer for a property key that is not set is 404 \"The property key was not found\". RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "software/Board" }
      - { method: "GET", path: "/rest/agile/1.0/board/{boardId}/quickfilter", area: "boards", tier: 1, status: "green", mode: "empty", mode_reason: "no board in this site has a quick filter CONFIGURED - a quick filter is part of a board's CONFIGURATION, and canon models none of it: the board this host renders is a team plus the saved filter it is defined by, and nothing in this universe carries the per-board clause list a quick filter is one of; Jira's own answer for a board with none is an empty page bean (total 0, values []) at 200. RULED by the founder 2026-09-12; RE-WORDED 2026-09-12 (hello-18 wave W-b, AUTONOMOUS RULING, seed brief F2) with the mode unmoved - the sentence used to rest on \"this universe accepts no writes\", and hello-18's savedFilters domain mints filters nobody typed, so that argument would have ruled out the eight /rest/api/3/filter/ rows this same wave serves. A BoardConfig entity (quick filters, columns, estimation field, ranking field) was deferred on its own merits and is not in hello-18", mode_reviewed: "2026-09-12", tag: "software/Board" }
      - { method: "GET", path: "/rest/agile/1.0/board/{boardId}/quickfilter/{quickFilterId}", area: "boards", tier: 1, status: "planned", mode: "refuse", mode_reason: "no board in this site has a quick filter CONFIGURED - a quick filter is part of a board's CONFIGURATION and canon models none of it, so no quickFilterId resolves; Jira's own answer is its 404 for the quick filter. RULED by the founder 2026-09-12; RE-WORDED 2026-09-12 (hello-18 wave W-b, AUTONOMOUS RULING, seed brief F2) with the mode unmoved, for the reason the list half's own entry gives", mode_reviewed: "2026-09-12", tag: "software/Board" }
      - { method: "GET", path: "/rest/agile/1.0/board/{boardId}/reports", area: "boards", tier: 1, status: "planned", mode: "generate", mode_reason: "new canon entity BoardConfig", mode_reviewed: "2026-09-01", tag: "software/Board" }
      - { method: "GET", path: "/rest/agile/1.0/board/{boardId}/sprint", area: "boards", tier: 1, status: "green", mode: "derive", tag: "software/Board" }
      - { method: "GET", path: "/rest/agile/1.0/board/{boardId}/sprint/{sprintId}/issue", area: "boards", tier: 1, status: "green", mode: "derive", mode_reason: "the same board/sprint/epic listings agile/1.0 already serves green", mode_reviewed: "2026-09-01", tag: "software/Board" }
      - { method: "GET", path: "/rest/agile/1.0/board/{boardId}/version", area: "boards", tier: 1, status: "green", mode: "derive", mode_reason: "canon releases and milestones, projected onto the project as Jira versions", mode_reviewed: "2026-09-01", tag: "software/Board" }
      - { method: "GET", path: "/rest/agile/1.0/board/filter/{filterId}", area: "boards", tier: 1, status: "green", mode: "derive", mode_reason: "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 board in this site IS defined by its filter — the savedFilters pass mints one board filter per team that tracks work — so this route answers with the one board whose filter the caller named, narrowed off renderBoard so the two routes cannot disagree about its name. A filter no board is built on (the personal and organization-wide ones) answers Jira's empty page bean: a true statement about a real filter rather than an absence", mode_reviewed: "2026-09-12", tag: "software/Board" }
      - { method: "GET", path: "/rest/agile/1.0/epic/{epicIdOrKey}", area: "epics", tier: 1, status: "green", mode: "derive", tag: "software/Epic" }
      - { method: "GET", path: "/rest/agile/1.0/epic/{epicIdOrKey}/issue", area: "epics", tier: 1, status: "green", mode: "derive", tag: "software/Epic" }
      - { method: "GET", path: "/rest/agile/1.0/epic/none/issue", area: "epics", tier: 1, status: "green", mode: "derive", tag: "software/Epic" }
      - { method: "GET", path: "/rest/agile/1.0/issue/{issueIdOrKey}", area: "agile-issues", tier: 1, status: "green", mode: "derive", tag: "software/Issue" }
      - { method: "GET", path: "/rest/agile/1.0/issue/{issueIdOrKey}/estimation", area: "agile-issues", tier: 1, status: "green", mode: "derive", tag: "software/Issue" }
      - { method: "GET", path: "/rest/agile/1.0/sprint/{sprintId}", area: "sprints", tier: 1, status: "green", mode: "derive", tag: "software/Sprint" }
      - { method: "GET", path: "/rest/agile/1.0/sprint/{sprintId}/issue", area: "sprints", tier: 1, status: "green", mode: "derive", tag: "software/Sprint" }
      - { method: "GET", path: "/rest/agile/1.0/sprint/{sprintId}/properties", area: "sprints", tier: 1, status: "green", mode: "empty", mode_reason: "no entity in this Jira site carries an app property - entity properties are written only by Connect/Forge apps through the API and olympus-labs installs none, and this universe accepts no writes; Jira's own answer for a property key that is not set is 404 \"The property key was not found\", and its answer for an entity that carries none is the empty `{\"keys\": []}` this operation declares. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "software/Sprint" }
      - { method: "GET", path: "/rest/agile/1.0/sprint/{sprintId}/properties/{propertyKey}", area: "sprints", tier: 1, status: "planned", mode: "refuse", mode_reason: "no entity in this Jira site carries an app property - entity properties are written only by Connect/Forge apps through the API and olympus-labs installs none, and this universe accepts no writes; Jira's own answer for a property key that is not set is 404 \"The property key was not found\". RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "software/Sprint" }
      - { method: "GET", path: "/rest/api/3/announcementBanner", area: "platform/announcement banner", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox token is a project-member token, not a Jira site admin — /rest/api/3/mypermissions already answers ADMINISTER havePermission=false, and real Jira Cloud answers 403 to this route for such a token", mode_reviewed: "2026-09-01", tag: "platform/Announcement banner", flag: "needs-tier-review" }
      - { method: "GET", path: "/rest/api/3/app/field/{fieldIdOrKey}/context/configuration", area: "apps", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no Connect or Forge app is installed on this site; these routes are addressed to an installed app's own scope and Jira answers 401/404 to a caller that is not that app", mode_reviewed: "2026-09-01", tag: "platform/Issue custom field configuration (apps)" }
      - { method: "GET", path: "/rest/api/3/application-properties", area: "admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox token is a project-member token, not a Jira site admin — /rest/api/3/mypermissions already answers ADMINISTER havePermission=false, and real Jira Cloud answers 403 to this route for such a token", mode_reviewed: "2026-09-01", tag: "platform/Jira settings" }
      - { method: "GET", path: "/rest/api/3/application-properties/advanced-settings", area: "admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox token is a project-member token, not a Jira site admin — /rest/api/3/mypermissions already answers ADMINISTER havePermission=false, and real Jira Cloud answers 403 to this route for such a token", mode_reviewed: "2026-09-01", tag: "platform/Jira settings" }
      - { method: "GET", path: "/rest/api/3/applicationrole", area: "platform/application roles", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox token is a project-member token, not a Jira site admin — /rest/api/3/mypermissions already answers ADMINISTER havePermission=false, and real Jira Cloud answers 403 to this route for such a token", mode_reviewed: "2026-09-01", tag: "platform/Application roles", flag: "needs-tier-review" }
      - { method: "GET", path: "/rest/api/3/applicationrole/{key}", area: "platform/application roles", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox token is a project-member token, not a Jira site admin — /rest/api/3/mypermissions already answers ADMINISTER havePermission=false, and real Jira Cloud answers 403 to this route for such a token", mode_reviewed: "2026-09-01", tag: "platform/Application roles", flag: "needs-tier-review" }
      - { method: "GET", path: "/rest/api/3/attachment/{id}", area: "attachments", tier: 2, status: "green", mode: "derive", mode_reason: "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. attachmentsForIssue() and attachmentsForIssueComment() — the files on a Jira ISSUE and on its comments, and only those: the support desk's 35+ files stay unreachable here because listAttachments() is scoped away from the engineering parents and these accessors are scoped away from the desk's. id, filename, author, created, size, mimeType and a content url that resolves; thumbnail only on an image, omitted rather than nulled so no published url dangles", mode_reviewed: "2026-09-12", tag: "platform/Issue attachments" }
      - { method: "GET", path: "/rest/api/3/attachment/{id}/expand/human", area: "attachments", tier: 2, status: "green", mode: "empty", mode_reason: "no attachment in this universe is an ARCHIVE - the operation itself declares the empty answer (\"if an empty list is returned in the response, the attachment is empty, corrupt, or not an archive\") and every canon.AttachmentKind is text a theme can WRITE: a YAML snippet, an SVG, a CSV, a log excerpt, a stack trace and a HAR summary, not one of them a ZIP. So the empty entry list is Jira's own true answer here, carrying the AttachmentMetadata this host publishes beside it. RULED 2026-09-12 (hello-18 wave W-b, autonomous), on the operation's own declared semantics", mode_reviewed: "2026-09-12", tag: "platform/Issue attachments" }
      - { method: "GET", path: "/rest/api/3/attachment/{id}/expand/raw", area: "attachments", tier: 2, status: "green", mode: "empty", mode_reason: "no attachment in this universe is an ARCHIVE - the operation itself declares the empty answer (\"if an empty list is returned in the response, the attachment is empty, corrupt, or not an archive\") and every canon.AttachmentKind is text a theme can WRITE: a YAML snippet, an SVG, a CSV, a log excerpt, a stack trace and a HAR summary, not one of them a ZIP. So the empty entry list is Jira's own true answer here, carrying the contents and nothing else, which is the documented difference from the human form. RULED 2026-09-12 (hello-18 wave W-b, autonomous), on the operation's own declared semantics", mode_reviewed: "2026-09-12", tag: "platform/Issue attachments" }
      - { method: "GET", path: "/rest/api/3/attachment/content/{id}", area: "attachments", tier: 2, status: "green", mode: "derive", mode_reason: "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 themselves: attachment.body, whose size_bytes and sha256 the compiler measured off exactly these bytes and which the conformance entry re-hashes. redirect=false serves them at 200; the default is Jira's 303 to /secure/attachment/{id}/{filename} — Jira's own non-REST download path, the /secure/useravatar precedent, so no endpoint is invented inside /rest/api/ (invariant #2) and the Location resolves (invariant #5)", mode_reviewed: "2026-09-12", tag: "platform/Issue attachments" }
      - { method: "GET", path: "/rest/api/3/attachment/meta", area: "attachments", tier: 2, status: "green", mode: "derive", mode_reason: "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. A SETTING rather than a file, which is why this is the one row of the family that is NOT gated on the generation: enabled reads hasAttachmentParents() — the same fact /rest/api/3/configuration's attachmentsEnabled now reads, so the two routes cannot disagree — and is honestly false on every pin. uploadLimit is Jira Cloud's own fixed 10 MB, the same class of provider constant as the status ids this renderer already carries", mode_reviewed: "2026-09-12", tag: "platform/Issue attachments" }
      - { method: "GET", path: "/rest/api/3/attachment/thumbnail/{id}", area: "attachments", tier: 2, status: "green", mode: "derive", mode_reason: "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 image itself: screenshot-svg is the one kind carrying width/height, and an SVG is a vector document, so serving it as its own thumbnail scales to whatever the client renders at and invents no pixel. A file that is NOT an image answers Jira's declared 404 for \"the requested thumbnail cannot be downloaded\" even with fallbackToDefault=true, because Jira's default thumbnail is Atlassian ARTWORK and this replica reproduces none of it (the same licence finding the system-avatar rows made)", mode_reviewed: "2026-09-12", tag: "platform/Issue attachments" }
      - { method: "GET", path: "/rest/api/3/auditing/record", area: "platform/audit records", tier: 3, status: "deferred", mode: "generate", mode_reason: "A WIDENING, NOT A BUILD: canon.AdminAuditEvent exists (packages/canon/src/support-desk.ts:690) and its own doc comment calls it \"GENERIC by construction\". The action vocabulary (AuditAction, :602), the change vocabulary (AuditChangeSlot, :633), the target vocabulary (AuditTargetKind, :611) and the RFC 5737 source-address rule (AuditSourceBlock, :652) all shipped, and Zendesk serves the table today (reader.listAuditEvents(), ruled 2026-09-07). TWO things are missing and neither is the entity: git-host members on AuditTargetKind, and a generation that WRITES personActor — the field is declared for exactly this wave and \"this generation writes none\" (:695-697)", mode_reviewed: "2026-09-09", tag: "platform/Audit records", flag: "needs-tier-review" }
      - { method: "GET", path: "/rest/api/3/avatar/{type}/system", area: "avatars", tier: 3, status: "green", mode: "derive", mode_reason: "reader.refCatalog(\"jira.system-avatars\") filtered by type, with the four urls composed onto /secure/useravatar?avatarId=&avatarType= (the operation's own example path, which this host already serves) and answered with identiconPng - this universe's own bytes, never Atlassian's artwork. licence: NO GRANT NEEDED — Avatar requires only id in the vendored description and urls are RELATIVE paths on this host, so the BYTES behind them are this universe's own: PersonAvatar has been canon since hello-13 and identiconPng already rasterises byte-identical avatars for GitHub, GitLab, Jira and ADO (packages/conformance/src/parity/avatar-parity.test.ts). Atlassian's artwork is never reproduced. Older pins answer the refCatalogs generation-gap 404 rather than an empty catalogue, which on these rows would be a false claim about the HOST. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", tag: "platform/Avatars" }
      - { method: "GET", path: "/rest/api/3/bulk/issues/fields", area: "bulk-ops", tier: 3, status: "green", mode: "derive", mode_reason: "the field registry in packages/renderer-jira/src/metadata.ts", mode_reviewed: "2026-09-01", tag: "platform/Issue bulk operations" }
      - { method: "GET", path: "/rest/api/3/bulk/issues/transition", area: "bulk-ops", tier: 3, status: "green", mode: "derive", mode_reason: "issue_transition rows plus the six-state workflow vocabulary", mode_reviewed: "2026-09-01", tag: "platform/Issue bulk operations" }
      - { method: "GET", path: "/rest/api/3/bulk/queue/{taskId}", area: "bulk-ops", tier: 3, status: "deferred", mode: "refuse", mode_reason: "this universe accepts no writes, so no asynchronous job was ever queued and no task id can resolve — Jira's own 404 for an unknown task is the whole answer", mode_reviewed: "2026-09-01", tag: "platform/Issue bulk operations" }
      - { method: "GET", path: "/rest/api/3/classification-levels", area: "platform/classification levels", tier: 3, status: "deferred", mode: "refuse", mode_reason: "data classification is an Atlassian Guard / Premium feature this site does not have, and Jira answers 403 to a token without the classification scope", mode_reviewed: "2026-09-01", tag: "platform/Classification levels", flag: "needs-tier-review" }
      - { method: "GET", path: "/rest/api/3/comment/{commentId}/properties", area: "properties", tier: 3, status: "green", mode: "empty", mode_reason: "no entity in this Jira site carries an app property - entity properties are written only by Connect/Forge apps through the API and olympus-labs installs none, and this universe accepts no writes; Jira's own answer for a property key that is not set is 404 \"The property key was not found\", and its answer for an entity that carries none is the empty `{\"keys\": []}` this operation declares. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "platform/Issue comment properties" }
      - { method: "GET", path: "/rest/api/3/comment/{commentId}/properties/{propertyKey}", area: "properties", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no entity in this Jira site carries an app property - entity properties are written only by Connect/Forge apps through the API and olympus-labs installs none, and this universe accepts no writes; Jira's own answer for a property key that is not set is 404 \"The property key was not found\". RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "platform/Issue comment properties" }
      - { method: "GET", path: "/rest/api/3/component", area: "versions-components", tier: 2, status: "green", mode: "derive", mode_reason: "the canon component rows the project's issues already reference", mode_reviewed: "2026-09-01", tag: "platform/Project components" }
      - { method: "GET", path: "/rest/api/3/component/{id}", area: "versions-components", tier: 2, status: "green", mode: "derive", mode_reason: "the canon component rows the project's issues already reference", mode_reviewed: "2026-09-01", tag: "platform/Project components" }
      - { method: "GET", path: "/rest/api/3/component/{id}/relatedIssueCounts", area: "versions-components", tier: 2, status: "green", mode: "derive", mode_reason: "the canon component rows the project's issues already reference", mode_reviewed: "2026-09-01", tag: "platform/Project components" }
      - { method: "GET", path: "/rest/api/3/config/fieldschemes", area: "field-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Field schemes" }
      - { method: "GET", path: "/rest/api/3/config/fieldschemes/{id}", area: "field-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Field schemes" }
      - { method: "GET", path: "/rest/api/3/config/fieldschemes/{id}/fields", area: "field-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Field schemes" }
      - { method: "GET", path: "/rest/api/3/config/fieldschemes/{id}/fields/{fieldId}/parameters", area: "field-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Field schemes" }
      - { method: "GET", path: "/rest/api/3/config/fieldschemes/{id}/projects", area: "field-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Field schemes" }
      - { method: "GET", path: "/rest/api/3/config/fieldschemes/projects", area: "field-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Field schemes" }
      - { method: "GET", path: "/rest/api/3/configuration", area: "admin", tier: 3, status: "green", mode: "derive", mode_reason: "the global-settings flags follow what this universe actually serves (voting, watching, attachments, sub-tasks, time tracking)", mode_reviewed: "2026-09-01", tag: "platform/Jira settings" }
      - { method: "GET", path: "/rest/api/3/configuration/timetracking", area: "time-tracking", tier: 2, status: "green", mode: "empty", mode_reason: "time tracking is not in use in this Jira site - no worklog exists and issue.estimate is a story-point estimate rather than a time estimate; Jira's own answer when no time tracking provider is selected is 204 No Content with an empty body. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "platform/Time tracking" }
      - { method: "GET", path: "/rest/api/3/configuration/timetracking/list", area: "time-tracking", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Worklog — the time-tracking configuration follows it", mode_reviewed: "2026-09-01", tag: "platform/Time tracking" }
      - { method: "GET", path: "/rest/api/3/configuration/timetracking/options", area: "time-tracking", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Worklog — the time-tracking configuration follows it", mode_reviewed: "2026-09-01", tag: "platform/Time tracking" }
      - { method: "GET", path: "/rest/api/3/customFieldOption/{id}", area: "field-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "neither custom field this universe defines (customfield_10016, customfield_10020) is a select field, so no option id can ever resolve — Jira's own 404 is the only possible answer", mode_reviewed: "2026-09-01", tag: "platform/Issue custom field options" }
      - { method: "GET", path: "/rest/api/3/dashboard", area: "dashboards", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Dashboard", mode_reviewed: "2026-09-01", tag: "platform/Dashboards" }
      - { method: "GET", path: "/rest/api/3/dashboard/{dashboardId}/gadget", area: "dashboards", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Dashboard", mode_reviewed: "2026-09-01", tag: "platform/Dashboards" }
      - { method: "GET", path: "/rest/api/3/dashboard/{dashboardId}/items/{itemId}/properties", area: "dashboards", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity EntityProperty", mode_reviewed: "2026-09-01", tag: "platform/Dashboards" }
      - { method: "GET", path: "/rest/api/3/dashboard/{dashboardId}/items/{itemId}/properties/{propertyKey}", area: "dashboards", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity EntityProperty", mode_reviewed: "2026-09-01", tag: "platform/Dashboards" }
      - { method: "GET", path: "/rest/api/3/dashboard/{id}", area: "dashboards", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Dashboard", mode_reviewed: "2026-09-01", tag: "platform/Dashboards" }
      - { method: "GET", path: "/rest/api/3/dashboard/gadgets", area: "dashboards", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Dashboard", mode_reviewed: "2026-09-01", tag: "platform/Dashboards" }
      - { method: "GET", path: "/rest/api/3/dashboard/search", area: "dashboards", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Dashboard", mode_reviewed: "2026-09-01", tag: "platform/Dashboards" }
      - { method: "GET", path: "/rest/api/3/data-policy", area: "platform/app data policies", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox token is a project-member token, not a Jira site admin — /rest/api/3/mypermissions already answers ADMINISTER havePermission=false, and real Jira Cloud answers 403 to this route for such a token", mode_reviewed: "2026-09-01", tag: "platform/App data policies", flag: "needs-tier-review" }
      - { method: "GET", path: "/rest/api/3/data-policy/project", area: "platform/app data policies", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox token is a project-member token, not a Jira site admin — /rest/api/3/mypermissions already answers ADMINISTER havePermission=false, and real Jira Cloud answers 403 to this route for such a token", mode_reviewed: "2026-09-01", tag: "platform/App data policies", flag: "needs-tier-review" }
      - { method: "GET", path: "/rest/api/3/events", area: "issues", tier: 1, status: "green", mode: "derive", mode_reason: "reader.refCatalog(\"jira.events\") in id order. licence: FACTUAL — the response is {id, name} event-type names (\"Issue Created\", \"Issue Updated\" in the vendored description's example), an enumeration of Jira's own notification triggers. Older pins answer the refCatalogs generation-gap 404 rather than an empty catalogue, which on these rows would be a false claim about the HOST. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", tag: "platform/Issues" }
      - { method: "GET", path: "/rest/api/3/field", area: "fields", tier: 1, status: "green", mode: "derive", tag: "platform/Issue fields" }
      - { method: "GET", path: "/rest/api/3/field/{fieldId}/association/project", area: "fields", tier: 1, status: "green", mode: "derive", mode_reason: "the field registry in packages/renderer-jira/src/metadata.ts — every field is on every project here", mode_reviewed: "2026-09-01", tag: "platform/Issue fields" }
      - { method: "GET", path: "/rest/api/3/field/{fieldId}/context", area: "field-admin", tier: 3, status: "green", mode: "derive", mode_reason: "the two custom fields (customfield_10016 story points, customfield_10020 sprint) and their single global context", mode_reviewed: "2026-09-01", tag: "platform/Issue custom field contexts" }
      - { method: "GET", path: "/rest/api/3/field/{fieldId}/context/{contextId}/option", area: "field-admin", tier: 3, status: "green", mode: "empty", mode_reason: "neither custom field this replica serves is an option field — customfield_10020 is an array of Greenhopper sprint blobs and customfield_10016 is a number — so their one context has no select-list option to list; the registry is fixed at compile time and this universe accepts no writes. RULED by the founder 2026-09-09", mode_reviewed: "2026-09-09", tag: "platform/Issue custom field options" }
      - { method: "GET", path: "/rest/api/3/field/{fieldId}/context/defaultValue", area: "field-admin", tier: 3, status: "green", mode: "empty", mode_reason: "neither custom field this replica serves carries a default value — customfield_10020 is an array of Greenhopper sprint blobs and customfield_10016 is a number, the registry is fixed at compile time and this universe accepts no writes — and Jira's own description says so for this route: 'If no defaults are set for a context, nothing is returned'. RULED by the founder 2026-09-09", mode_reviewed: "2026-09-09", tag: "platform/Issue custom field contexts" }
      - { method: "GET", path: "/rest/api/3/field/{fieldId}/context/defaultValues", area: "field-admin", tier: 3, status: "green", mode: "empty", mode_reason: "the same two fields carry no default grouped by context either, so the page that groups them has nothing to group; the registry is fixed at compile time and this universe accepts no writes. RULED by the founder 2026-09-09", mode_reviewed: "2026-09-09", tag: "platform/Issue custom field contexts" }
      - { method: "GET", path: "/rest/api/3/field/{fieldId}/context/issuetypemapping", area: "field-admin", tier: 3, status: "green", mode: "derive", mode_reason: "the two custom fields (customfield_10016 story points, customfield_10020 sprint) and their single global context", mode_reviewed: "2026-09-01", tag: "platform/Issue custom field contexts" }
      - { method: "GET", path: "/rest/api/3/field/{fieldId}/context/projectmapping", area: "field-admin", tier: 3, status: "green", mode: "derive", mode_reason: "the two custom fields (customfield_10016 story points, customfield_10020 sprint) and their single global context", mode_reviewed: "2026-09-01", tag: "platform/Issue custom field contexts" }
      - { method: "GET", path: "/rest/api/3/field/{fieldId}/contexts", area: "fields", tier: 1, status: "green", mode: "derive", mode_reason: "the field registry in packages/renderer-jira/src/metadata.ts", mode_reviewed: "2026-09-01", tag: "platform/Issue fields" }
      - { method: "GET", path: "/rest/api/3/field/{fieldId}/screens", area: "screen-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Screens" }
      - { method: "GET", path: "/rest/api/3/field/{fieldKey}/option", area: "apps", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no Connect or Forge app is installed on this site; these routes are addressed to an installed app's own scope and Jira answers 401/404 to a caller that is not that app", mode_reviewed: "2026-09-01", tag: "platform/Issue custom field options (apps)" }
      - { method: "GET", path: "/rest/api/3/field/{fieldKey}/option/{optionId}", area: "apps", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no Connect or Forge app is installed on this site; these routes are addressed to an installed app's own scope and Jira answers 401/404 to a caller that is not that app", mode_reviewed: "2026-09-01", tag: "platform/Issue custom field options (apps)" }
      - { method: "GET", path: "/rest/api/3/field/{fieldKey}/option/suggestions/edit", area: "apps", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no Connect or Forge app is installed on this site; these routes are addressed to an installed app's own scope and Jira answers 401/404 to a caller that is not that app", mode_reviewed: "2026-09-01", tag: "platform/Issue custom field options (apps)" }
      - { method: "GET", path: "/rest/api/3/field/{fieldKey}/option/suggestions/search", area: "apps", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no Connect or Forge app is installed on this site; these routes are addressed to an installed app's own scope and Jira answers 401/404 to a caller that is not that app", mode_reviewed: "2026-09-01", tag: "platform/Issue custom field options (apps)" }
      - { method: "GET", path: "/rest/api/3/field/search", area: "fields", tier: 1, status: "green", mode: "derive", mode_reason: "the field registry in packages/renderer-jira/src/metadata.ts", mode_reviewed: "2026-09-01", tag: "platform/Issue fields" }
      - { method: "GET", path: "/rest/api/3/field/search/trashed", area: "fields", tier: 1, status: "green", mode: "empty", mode_reason: "no field has ever been deleted in this universe — the field registry is fixed at compile time and this universe accepts no writes — so the field trash is truthfully an empty page", mode_reviewed: "2026-09-01", tag: "platform/Issue fields" }
      - { method: "GET", path: "/rest/api/3/fieldconfiguration", area: "field-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Issue field configurations" }
      - { method: "GET", path: "/rest/api/3/fieldconfiguration/{id}/fields", area: "field-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Issue field configurations" }
      - { method: "GET", path: "/rest/api/3/fieldconfigurationscheme", area: "field-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Issue field configurations" }
      - { method: "GET", path: "/rest/api/3/fieldconfigurationscheme/mapping", area: "field-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Issue field configurations" }
      - { method: "GET", path: "/rest/api/3/fieldconfigurationscheme/project", area: "field-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Issue field configurations" }
      - { method: "GET", path: "/rest/api/3/filter/{id}", area: "filters", tier: 2, status: "green", mode: "derive", mode_reason: "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 filter object: id, name, owner, the baked jql verbatim, viewUrl, searchUrl, favourite, favouritedCount, sharePermissions from the share scope and Jira's empty FilterSubscriptionsList. description, approximateLastUsed, editPermissions and sharedUsers are OMITTED rather than invented — canon records none of the four and only name is required", mode_reviewed: "2026-09-12", tag: "platform/Filters" }
      - { method: "GET", path: "/rest/api/3/filter/{id}/columns", area: "filters", tier: 2, status: "deferred", mode: "refuse", mode_reason: "no filter in this site carries a column configuration of its own - a filter's columns are set by its owner in the issue navigator, canon's saved_filter records a QUERY and not a column set, and this universe accepts no writes; Jira's own answer for a filter with none is the 404 this operation declares in as many words (\"Returned if a column configuration is not set for the filter\"). THE SIBLING ROUTE GOES THE OTHER WAY AND THE DOCUMENT IS WHY: /rest/api/3/user/columns is a derive row serving the SITE DEFAULT because real Jira falls back to it for a user who configured none, and this operation declares no such fallback. The default columns a filter's results are viewed with are still readable, at /rest/api/3/settings/columns and /rest/api/3/user/columns. RULED 2026-09-12 (hello-18 wave W-b, autonomous)", mode_reviewed: "2026-09-12", tag: "platform/Filters" }
      - { method: "GET", path: "/rest/api/3/filter/{id}/permission", area: "filters", tier: 2, status: "green", mode: "derive", mode_reason: "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 same array Filter.sharePermissions carries, from saved_filter.share_scope: private is Jira's empty list, org is one loggedin permission (its own word for every logged-in user, where global would include anonymous access this site does not have), team is a project permission naming that team's project", mode_reviewed: "2026-09-12", tag: "platform/Filter sharing" }
      - { method: "GET", path: "/rest/api/3/filter/{id}/permission/{permissionId}", area: "filters", tier: 2, status: "green", mode: "derive", mode_reason: "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 single read off that same list — the conformance entry discovers the id THROUGH the list route and asserts the object comes back identical, so the id the list hands out is the id this route accepts. A private filter has no permission, so every id 404s there, which is the operation's own declared answer", mode_reviewed: "2026-09-12", tag: "platform/Filter sharing" }
      - { method: "GET", path: "/rest/api/3/filter/defaultShareScope", area: "filters", tier: 2, status: "green", mode: "derive", mode_reason: "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. PRIVATE, and the artifact says so: every filter a person saved FOR THEMSELVES — kind = mine, the only kind the pass mints per person — carries share_scope = private, and the wider ones are wide because of what they ARE. The conformance entry asserts that link rather than the constant", mode_reviewed: "2026-09-12", tag: "platform/Filter sharing" }
      - { method: "GET", path: "/rest/api/3/filter/favourite", area: "filters", tier: 2, status: "green", mode: "derive", mode_reason: "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 CALLER's stars: saved_filter.favourite records the owner's star (1 when the filter selects work in an active sprint), and Jira documents Filter.favourite as the calling user's, so this list is the filters this replica's viewer owns AND starred. Non-empty at both windows because that viewer owns the organization-wide filter", mode_reviewed: "2026-09-12", tag: "platform/Filters" }
      - { method: "GET", path: "/rest/api/3/filter/my", area: "filters", tier: 2, status: "green", mode: "derive", mode_reason: "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. listSavedFilters(\"jira\", caller) — the filters this replica's viewer OWNS, which is what the operation asks for; includeFavourites=true is honoured and adds the ones they starred, all of which they already own", mode_reviewed: "2026-09-12", tag: "platform/Filters" }
      - { method: "GET", path: "/rest/api/3/filter/search", area: "filters", tier: 2, status: "green", mode: "derive", mode_reason: "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 paged search over every filter in the site, with filterName, accountId, id and projectId answered from canon and the documented orderBy set. FilterDetails.favourite is FALSE on every row and that is the document's own reading — it is defined as \"by any users, NOT including the filter owner\", and the only star canon records is the owner's, which favouritedCount (defined as including the owner) carries instead", mode_reviewed: "2026-09-12", tag: "platform/Filters" }
      - { method: "GET", path: "/rest/api/3/group", area: "groups", tier: 1, status: "green", mode: "derive", tag: "platform/Groups" }
      - { method: "GET", path: "/rest/api/3/group/bulk", area: "groups", tier: 1, status: "green", mode: "derive", mode_reason: "the group table the renderer already renders (site group + one per team)", mode_reviewed: "2026-09-01", tag: "platform/Groups" }
      - { method: "GET", path: "/rest/api/3/group/member", area: "groups", tier: 1, status: "green", mode: "derive", tag: "platform/Groups" }
      - { method: "GET", path: "/rest/api/3/groups/picker", area: "groups", tier: 1, status: "green", mode: "derive", tag: "platform/Groups" }
      - { method: "GET", path: "/rest/api/3/groupuserpicker", area: "platform/group and user picker", tier: 3, status: "green", mode: "derive", mode_reason: "the person table — the same users /rest/api/3/user already renders", mode_reviewed: "2026-09-01", tag: "platform/Group and user picker", flag: "needs-tier-review" }
      - { method: "GET", path: "/rest/api/3/instance/license", area: "admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox token is a project-member token, not a Jira site admin — /rest/api/3/mypermissions already answers ADMINISTER havePermission=false, and real Jira Cloud answers 403 to this route for such a token", mode_reviewed: "2026-09-01", tag: "platform/License metrics" }
      - { method: "GET", path: "/rest/api/3/issue/{issueIdOrKey}", area: "issues", tier: 1, status: "green", mode: "derive", tag: "platform/Issues" }
      - { method: "GET", path: "/rest/api/3/issue/{issueIdOrKey}/changelog", area: "issues", tier: 1, status: "green", mode: "derive", tag: "platform/Issues" }
      - { method: "GET", path: "/rest/api/3/issue/{issueIdOrKey}/comment", area: "issues", tier: 1, status: "green", mode: "derive", tag: "platform/Issue comments" }
      - { method: "GET", path: "/rest/api/3/issue/{issueIdOrKey}/comment/{id}", area: "issues", tier: 1, status: "green", mode: "derive", tag: "platform/Issue comments" }
      - { method: "GET", path: "/rest/api/3/issue/{issueIdOrKey}/editmeta", area: "issues", tier: 1, status: "green", mode: "derive", mode_reason: "the field registry in packages/renderer-jira/src/metadata.ts crossed with the issue-type vocabulary", mode_reviewed: "2026-09-01", tag: "platform/Issues" }
      - { method: "GET", path: "/rest/api/3/issue/{issueIdOrKey}/properties", area: "properties", tier: 3, status: "green", mode: "empty", mode_reason: "no entity in this Jira site carries an app property - entity properties are written only by Connect/Forge apps through the API and olympus-labs installs none, and this universe accepts no writes; Jira's own answer for a property key that is not set is 404 \"The property key was not found\", and its answer for an entity that carries none is the empty `{\"keys\": []}` this operation declares. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "platform/Issue properties" }
      - { method: "GET", path: "/rest/api/3/issue/{issueIdOrKey}/properties/{propertyKey}", area: "properties", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no entity in this Jira site carries an app property - entity properties are written only by Connect/Forge apps through the API and olympus-labs installs none, and this universe accepts no writes; Jira's own answer for a property key that is not set is 404 \"The property key was not found\". RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "platform/Issue properties" }
      - { method: "GET", path: "/rest/api/3/issue/{issueIdOrKey}/remotelink", area: "issue-links", tier: 2, status: "green", mode: "empty", mode_reason: "no issue and no version in olympus-labs carries a remote link - a remote link is an application link to an object in another Atlassian product and this site has no linked Confluence, no linked Bitbucket and no app; Jira's own answer for an issue with none is [] at 200. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "platform/Issue remote links" }
      - { method: "GET", path: "/rest/api/3/issue/{issueIdOrKey}/remotelink/{linkId}", area: "issue-links", tier: 2, status: "deferred", mode: "refuse", mode_reason: "no issue and no version in olympus-labs carries a remote link - a remote link is an application link to an object in another Atlassian product and this site has no linked Confluence, no linked Bitbucket and no app, so no link id resolves and Jira's own 404 is the whole answer. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "platform/Issue remote links" }
      - { method: "GET", path: "/rest/api/3/issue/{issueIdOrKey}/transitions", area: "issues", tier: 1, status: "green", mode: "derive", mode_reason: "issue_transition rows plus the six-state workflow vocabulary", mode_reviewed: "2026-09-01", tag: "platform/Issues" }
      - { method: "GET", path: "/rest/api/3/issue/{issueIdOrKey}/votes", area: "issue-extras", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity IssueWatch", mode_reviewed: "2026-09-01", tag: "platform/Issue votes" }
      - { method: "GET", path: "/rest/api/3/issue/{issueIdOrKey}/watchers", area: "issue-extras", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity IssueWatch", mode_reviewed: "2026-09-01", tag: "platform/Issue watchers" }
      - { method: "GET", path: "/rest/api/3/issue/{issueIdOrKey}/worklog", area: "worklogs", tier: 2, status: "green", mode: "empty", mode_reason: "nobody in olympus-labs logs time - the generator writes an estimate on an issue (issue.estimate) and never a worklog, so no work log has ever been created, updated or deleted in this universe; Jira's own answer for an issue with none is {\"worklogs\": [], \"total\": 0} at 200 and for the updated/deleted feeds an empty values list with the window's until time. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "platform/Issue worklogs" }
      - { method: "GET", path: "/rest/api/3/issue/{issueIdOrKey}/worklog/{id}", area: "worklogs", tier: 2, status: "deferred", mode: "refuse", mode_reason: "nobody in olympus-labs logs time - the generator writes an estimate on an issue (issue.estimate) and never a worklog, so no work log has ever been created and no worklog id resolves; Jira's own 404 for a worklog that is not found is the whole answer. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "platform/Issue worklogs" }
      - { method: "GET", path: "/rest/api/3/issue/{issueIdOrKey}/worklog/{worklogId}/properties", area: "properties", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity EntityProperty", mode_reviewed: "2026-09-01", tag: "platform/Issue worklog properties" }
      - { method: "GET", path: "/rest/api/3/issue/{issueIdOrKey}/worklog/{worklogId}/properties/{propertyKey}", area: "properties", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity EntityProperty", mode_reviewed: "2026-09-01", tag: "platform/Issue worklog properties" }
      - { method: "GET", path: "/rest/api/3/issue/createmeta", area: "issues", tier: 1, status: "green", mode: "derive", mode_reason: "the field registry in packages/renderer-jira/src/metadata.ts crossed with the issue-type vocabulary", mode_reviewed: "2026-09-01", tag: "platform/Issues" }
      - { method: "GET", path: "/rest/api/3/issue/createmeta/{projectIdOrKey}/issuetypes", area: "issues", tier: 1, status: "green", mode: "derive", mode_reason: "the field registry in packages/renderer-jira/src/metadata.ts crossed with the issue-type vocabulary", mode_reviewed: "2026-09-01", tag: "platform/Issues" }
      - { method: "GET", path: "/rest/api/3/issue/createmeta/{projectIdOrKey}/issuetypes/{issueTypeId}", area: "issues", tier: 1, status: "green", mode: "derive", mode_reason: "the field registry in packages/renderer-jira/src/metadata.ts crossed with the issue-type vocabulary", mode_reviewed: "2026-09-01", tag: "platform/Issues" }
      - { method: "GET", path: "/rest/api/3/issue/limit/report", area: "issues", tier: 1, status: "planned", mode: "refuse", mode_reason: "the sandbox token is a project-member token, not a Jira site admin — /rest/api/3/mypermissions already answers ADMINISTER havePermission=false, and real Jira Cloud answers 403 to this route for such a token", mode_reviewed: "2026-09-01", tag: "platform/Issues" }
      - { method: "GET", path: "/rest/api/3/issue/picker", area: "search", tier: 1, status: "green", mode: "derive", mode_reason: "the issue table through the covered JQL engine", mode_reviewed: "2026-09-01", tag: "platform/Issue search" }
      - { method: "GET", path: "/rest/api/3/issueLink/{linkId}", area: "issue-links", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): one link with BOTH ends named, from canon's issue_link — the entity the 2026-09-01 classification called \"the A7 wave's\" and hello-17's features.issueLinks delivered. One row per adjacent pair inside one (epic, sprint) group, `blocks` when the earlier issue closed strictly before the later one opened and `relates` otherwise (decisions/2026-09-11-0200-hello-17-review-policy-social-graph-and-issue-links.md). inwardIssue IS THE SOURCE: the vendored IssueLink labels inwardIssue with the type's `inward` string and outwardIssue with its `outward`, and a link renders on one issue by dropping that end — substituting the description's own getIssueLink example (type Duplicate, inwardIssue PR-3, outwardIssue PR-2) that reads \"PR-3 Duplicates PR-2\" and \"PR-2 Duplicated by PR-3\", which is the only assignment of the two that says one thing. So the prerequisite is inwardIssue and its successor outwardIssue. Each end carries the four `Fields` this replica can answer from canon (summary, status, priority, issuetype), byte-identical to what /rest/api/3/issue/{key} prints for the same issue. Older artifacts answer the noIssueLinks generation-gap 404 naming generation hello-17 — never Jira's entity 404, which would be an answer about the id where the truth is that the universe has no links to have ids", mode_reviewed: "2026-09-12", tag: "platform/Issue links" }
      - { method: "GET", path: "/rest/api/3/issueLinkType", area: "issue-links", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): {issueLinkTypes: [...]}, the two relationships this site defines, id-ordered. TWO AND NOT FOUR: canon's kind vocabulary is closed at blocks|relates|duplicates|parent and this universe writes rows for the first two only — canon marks no duplicate anywhere, and its parentage runs issue -> EPIC, which is not an issue, so a `parent` row would be a reference that does not resolve in the table its column names. A catalogue advertising a type nothing can be is invariant #5 from the other end (the TYPE_DEFS rule renderer-ado takes), so it publishes exactly the kinds canon produces and grows on its own the day canon produces a third. THE VOCABULARY IS JIRA CLOUD'S SHIPPED DEFAULTS, NOT THE DOCUMENT'S EXAMPLE: IssueLinkType declares four strings and no enum, and the description's only concrete vocabulary is an illustrative example on getIssueLinkTypes ({id 1010, inward \"Blocked by\", name \"Blocks\", outward \"Blocks\"}) that no Jira Cloud site actually serves — every Cloud site is created with \"blocks\"/\"is blocked by\" and \"relates to\"/\"relates to\", which is what a client's UI and a human's JQL meet, so that is what an exact mirror serves. The divergence is recorded in packages/renderer-jira/src/issue-links.ts and in the decision entry. `[]` is not the answer on an older artifact: it would say this SITE defines no link types, a claim about the host (the noRefCatalogs precedent), so those answer the named generation gap", mode_reviewed: "2026-09-12", tag: "platform/Issue link types" }
      - { method: "GET", path: "/rest/api/3/issueLinkType/{issueLinkTypeId}", area: "issue-links", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): the same catalogue row by id, byte-identical to the one the list publishes — conformance asserts both types both ways. An id the catalogue does not carry is Jira's own 404 and not a coverage miss: the catalogue resolved and this id is not in it. Older artifacts answer the noIssueLinks generation gap, like the list", mode_reviewed: "2026-09-12", tag: "platform/Issue link types" }
      - { method: "GET", path: "/rest/api/3/issuesecurityschemes", area: "security-admin", tier: 3, status: "green", mode: "empty", mode_reason: "no issue security scheme exists in this Jira site - canon models no issue-level security and every issue in the one project is visible to every member; Jira creates no issue security scheme with a site and its own answer for a site with none is {\"issueSecuritySchemes\": []} at 200 (an empty page bean on the paged siblings). RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "platform/Issue security schemes" }
      - { method: "GET", path: "/rest/api/3/issuesecurityschemes/{id}", area: "security-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no issue security scheme exists in this Jira site - canon models no issue-level security and every issue in the one project is visible to every member; the LIST is an honest empty at 200, so this replica is plainly allowed to read schemes and an id over that empty collection can only be Jira's own 404. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "platform/Issue security schemes" }
      - { method: "GET", path: "/rest/api/3/issuesecurityschemes/{issueSecuritySchemeId}/members", area: "security-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no issue security scheme exists in this Jira site - canon models no issue-level security and every issue in the one project is visible to every member; the LIST is an honest empty at 200, so this replica is plainly allowed to read schemes and an id over that empty collection can only be Jira's own 404. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "platform/Issue security level" }
      - { method: "GET", path: "/rest/api/3/issuesecurityschemes/level", area: "security-admin", tier: 3, status: "green", mode: "empty", mode_reason: "no issue security scheme exists in this Jira site - canon models no issue-level security and every issue in the one project is visible to every member; Jira creates no issue security scheme with a site and its own answer for a site with none is {\"issueSecuritySchemes\": []} at 200 (an empty page bean on the paged siblings). RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "platform/Issue security schemes" }
      - { method: "GET", path: "/rest/api/3/issuesecurityschemes/level/member", area: "security-admin", tier: 3, status: "green", mode: "empty", mode_reason: "no issue security scheme exists in this Jira site - canon models no issue-level security and every issue in the one project is visible to every member; Jira creates no issue security scheme with a site and its own answer for a site with none is {\"issueSecuritySchemes\": []} at 200 (an empty page bean on the paged siblings). RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "platform/Issue security schemes" }
      - { method: "GET", path: "/rest/api/3/issuesecurityschemes/project", area: "security-admin", tier: 3, status: "green", mode: "empty", mode_reason: "no issue security scheme exists in this Jira site - canon models no issue-level security and every issue in the one project is visible to every member; Jira creates no issue security scheme with a site and its own answer for a site with none is {\"issueSecuritySchemes\": []} at 200 (an empty page bean on the paged siblings). RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "platform/Issue security schemes" }
      - { method: "GET", path: "/rest/api/3/issuesecurityschemes/search", area: "security-admin", tier: 3, status: "green", mode: "empty", mode_reason: "no issue security scheme exists in this Jira site - canon models no issue-level security and every issue in the one project is visible to every member; Jira creates no issue security scheme with a site and its own answer for a site with none is {\"issueSecuritySchemes\": []} at 200 (an empty page bean on the paged siblings). RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "platform/Issue security schemes" }
      - { method: "GET", path: "/rest/api/3/issuetype", area: "metadata", tier: 1, status: "green", mode: "derive", tag: "platform/Issue types" }
      - { method: "GET", path: "/rest/api/3/issuetype/{id}", area: "metadata", tier: 1, status: "green", mode: "derive", tag: "platform/Issue types" }
      - { method: "GET", path: "/rest/api/3/issuetype/{id}/alternatives", area: "metadata", tier: 1, status: "green", mode: "derive", mode_reason: "the status/type/priority/resolution vocabulary the renderer already serves green", mode_reviewed: "2026-09-01", tag: "platform/Issue types" }
      - { method: "GET", path: "/rest/api/3/issuetype/{issueTypeId}/properties", area: "properties", tier: 3, status: "green", mode: "empty", mode_reason: "no entity in this Jira site carries an app property - entity properties are written only by Connect/Forge apps through the API and olympus-labs installs none, and this universe accepts no writes; Jira's own answer for a property key that is not set is 404 \"The property key was not found\", and its answer for an entity that carries none is the empty `{\"keys\": []}` this operation declares. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "platform/Issue type properties" }
      - { method: "GET", path: "/rest/api/3/issuetype/{issueTypeId}/properties/{propertyKey}", area: "properties", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no entity in this Jira site carries an app property - entity properties are written only by Connect/Forge apps through the API and olympus-labs installs none, and this universe accepts no writes; Jira's own answer for a property key that is not set is 404 \"The property key was not found\". RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "platform/Issue type properties" }
      - { method: "GET", path: "/rest/api/3/issuetype/project", area: "metadata", tier: 1, status: "green", mode: "derive", mode_reason: "the status/type/priority/resolution vocabulary the renderer already serves green", mode_reviewed: "2026-09-01", tag: "platform/Issue types" }
      - { method: "GET", path: "/rest/api/3/issuetypescheme", area: "type-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Issue type schemes" }
      - { method: "GET", path: "/rest/api/3/issuetypescheme/mapping", area: "type-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Issue type schemes" }
      - { method: "GET", path: "/rest/api/3/issuetypescheme/project", area: "type-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Issue type schemes" }
      - { method: "GET", path: "/rest/api/3/issuetypescreenscheme", area: "screen-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Issue type screen schemes" }
      - { method: "GET", path: "/rest/api/3/issuetypescreenscheme/{issueTypeScreenSchemeId}/project", area: "screen-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Issue type screen schemes" }
      - { method: "GET", path: "/rest/api/3/issuetypescreenscheme/mapping", area: "screen-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Issue type screen schemes" }
      - { method: "GET", path: "/rest/api/3/issuetypescreenscheme/project", area: "screen-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Issue type screen schemes" }
      - { method: "GET", path: "/rest/api/3/jql/autocompletedata", area: "jql", tier: 1, status: "green", mode: "derive", tag: "platform/JQL" }
      - { method: "GET", path: "/rest/api/3/jql/autocompletedata/suggestions", area: "jql", tier: 1, status: "green", mode: "derive", mode_reason: "the covered JQL grammar and its values", mode_reviewed: "2026-09-01", tag: "platform/JQL" }
      - { method: "GET", path: "/rest/api/3/jql/function/computation", area: "apps", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no Connect or Forge app is installed on this site; these routes are addressed to an installed app's own scope and Jira answers 401/404 to a caller that is not that app", mode_reviewed: "2026-09-01", tag: "platform/JQL functions (apps)" }
      - { method: "GET", path: "/rest/api/3/label", area: "platform/labels", tier: 3, status: "green", mode: "derive", mode_reason: "the label table", mode_reviewed: "2026-09-01", tag: "platform/Labels", flag: "needs-tier-review" }
      - { method: "GET", path: "/rest/api/3/license/approximateLicenseCount", area: "admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox token is a project-member token, not a Jira site admin — /rest/api/3/mypermissions already answers ADMINISTER havePermission=false, and real Jira Cloud answers 403 to this route for such a token", mode_reviewed: "2026-09-01", tag: "platform/License metrics" }
      - { method: "GET", path: "/rest/api/3/license/approximateLicenseCount/product/{applicationKey}", area: "admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox token is a project-member token, not a Jira site admin — /rest/api/3/mypermissions already answers ADMINISTER havePermission=false, and real Jira Cloud answers 403 to this route for such a token", mode_reviewed: "2026-09-01", tag: "platform/License metrics" }
      - { method: "GET", path: "/rest/api/3/mypermissions", area: "permissions", tier: 1, status: "green", mode: "derive", tag: "platform/Permissions" }
      - { method: "GET", path: "/rest/api/3/mypreferences", area: "myself", tier: 1, status: "planned", mode: "refuse", mode_reason: "no person in olympus-labs has set a Jira user preference - canon records no per-user Jira setting and this universe accepts no writes; the key parameter is required and Jira's own answer for a key the caller has not set is 404 \"The preference with the given key does not exist\" (/mypreferences/locale stays served: it is the site locale, not a preference). RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "platform/Myself" }
      - { method: "GET", path: "/rest/api/3/mypreferences/locale", area: "myself", tier: 1, status: "green", mode: "derive", mode_reason: "the person table — the same users /rest/api/3/user already renders", mode_reviewed: "2026-09-01", tag: "platform/Myself" }
      - { method: "GET", path: "/rest/api/3/myself", area: "myself", tier: 1, status: "green", mode: "derive", tag: "platform/Myself" }
      - { method: "GET", path: "/rest/api/3/notificationscheme", area: "notification-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Issue notification schemes" }
      - { method: "GET", path: "/rest/api/3/notificationscheme/{id}", area: "notification-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Issue notification schemes" }
      - { method: "GET", path: "/rest/api/3/notificationscheme/project", area: "notification-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Issue notification schemes" }
      - { method: "GET", path: "/rest/api/3/permissions", area: "permissions", tier: 1, status: "green", mode: "derive", mode_reason: "the permission vocabulary /rest/api/3/mypermissions already answers", mode_reviewed: "2026-09-01", tag: "platform/Permissions" }
      - { method: "GET", path: "/rest/api/3/permissionscheme", area: "permission-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Permission schemes" }
      - { method: "GET", path: "/rest/api/3/permissionscheme/{schemeId}", area: "permission-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Permission schemes" }
      - { method: "GET", path: "/rest/api/3/permissionscheme/{schemeId}/permission", area: "permission-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Permission schemes" }
      - { method: "GET", path: "/rest/api/3/permissionscheme/{schemeId}/permission/{permissionId}", area: "permission-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Permission schemes" }
      - { method: "GET", path: "/rest/api/3/plans/plan", area: "plans", tier: 3, status: "deferred", mode: "refuse", mode_reason: "Advanced Roadmaps is a Jira Premium feature this site does not have; all five operations declare a 403 described as \"Returned if the site has no premium edition of Jira or if the user does not have the Administer Jira global permission\" - the ruled ground verbatim - so Jira answers 403, not 404, to plans reads on a site without the edition (founder ruling 2026-09-03 on proposal 1 of coverage/reviews/2026-09-03-jira-refuse-shapes.md)", mode_reviewed: "2026-09-03", tag: "platform/Plans" }
      - { method: "GET", path: "/rest/api/3/plans/plan/{planId}", area: "plans", tier: 3, status: "deferred", mode: "refuse", mode_reason: "Advanced Roadmaps is a Jira Premium feature this site does not have; all five operations declare a 403 described as \"Returned if the site has no premium edition of Jira or if the user does not have the Administer Jira global permission\" - the ruled ground verbatim - so Jira answers 403, not 404, to plans reads on a site without the edition (founder ruling 2026-09-03 on proposal 1 of coverage/reviews/2026-09-03-jira-refuse-shapes.md)", mode_reviewed: "2026-09-03", tag: "platform/Plans" }
      - { method: "GET", path: "/rest/api/3/plans/plan/{planId}/team", area: "plans", tier: 3, status: "deferred", mode: "refuse", mode_reason: "Advanced Roadmaps is a Jira Premium feature this site does not have; all five operations declare a 403 described as \"Returned if the site has no premium edition of Jira or if the user does not have the Administer Jira global permission\" - the ruled ground verbatim - so Jira answers 403, not 404, to plans reads on a site without the edition (founder ruling 2026-09-03 on proposal 1 of coverage/reviews/2026-09-03-jira-refuse-shapes.md)", mode_reviewed: "2026-09-03", tag: "platform/Teams in plan" }
      - { method: "GET", path: "/rest/api/3/plans/plan/{planId}/team/atlassian/{atlassianTeamId}", area: "plans", tier: 3, status: "deferred", mode: "refuse", mode_reason: "Advanced Roadmaps is a Jira Premium feature this site does not have; all five operations declare a 403 described as \"Returned if the site has no premium edition of Jira or if the user does not have the Administer Jira global permission\" - the ruled ground verbatim - so Jira answers 403, not 404, to plans reads on a site without the edition (founder ruling 2026-09-03 on proposal 1 of coverage/reviews/2026-09-03-jira-refuse-shapes.md)", mode_reviewed: "2026-09-03", tag: "platform/Teams in plan" }
      - { method: "GET", path: "/rest/api/3/plans/plan/{planId}/team/planonly/{planOnlyTeamId}", area: "plans", tier: 3, status: "deferred", mode: "refuse", mode_reason: "Advanced Roadmaps is a Jira Premium feature this site does not have; all five operations declare a 403 described as \"Returned if the site has no premium edition of Jira or if the user does not have the Administer Jira global permission\" - the ruled ground verbatim - so Jira answers 403, not 404, to plans reads on a site without the edition (founder ruling 2026-09-03 on proposal 1 of coverage/reviews/2026-09-03-jira-refuse-shapes.md)", mode_reviewed: "2026-09-03", tag: "platform/Teams in plan" }
      - { method: "GET", path: "/rest/api/3/priority", area: "metadata", tier: 1, status: "green", mode: "derive", tag: "platform/Issue priorities" }
      - { method: "GET", path: "/rest/api/3/priority/{id}", area: "metadata", tier: 1, status: "green", mode: "derive", tag: "platform/Issue priorities" }
      - { method: "GET", path: "/rest/api/3/priority/search", area: "metadata", tier: 1, status: "green", mode: "derive", mode_reason: "the status/type/priority/resolution vocabulary the renderer already serves green", mode_reviewed: "2026-09-01", tag: "platform/Issue priorities" }
      - { method: "GET", path: "/rest/api/3/priorityscheme", area: "metadata-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Priority schemes" }
      - { method: "GET", path: "/rest/api/3/priorityscheme/{schemeId}/priorities", area: "metadata-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Priority schemes" }
      - { method: "GET", path: "/rest/api/3/priorityscheme/{schemeId}/projects", area: "metadata-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Priority schemes" }
      - { method: "GET", path: "/rest/api/3/priorityscheme/priorities/available", area: "metadata-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Priority schemes" }
      - { method: "GET", path: "/rest/api/3/project", area: "projects", tier: 1, status: "green", mode: "derive", tag: "platform/Projects" }
      - { method: "GET", path: "/rest/api/3/project-template/live-template", area: "project-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox token is a project-member token, not a Jira site admin — /rest/api/3/mypermissions already answers ADMINISTER havePermission=false, and real Jira Cloud answers 403 to this route for such a token", mode_reviewed: "2026-09-01", tag: "platform/Project templates" }
      - { method: "GET", path: "/rest/api/3/project/{projectId}/email", area: "platform/project email", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity ProjectSetting", mode_reviewed: "2026-09-01", tag: "platform/Project email", flag: "needs-tier-review" }
      - { method: "GET", path: "/rest/api/3/project/{projectId}/hierarchy", area: "projects", tier: 1, status: "green", mode: "derive", mode_reason: "the status/type/priority/resolution vocabulary the renderer already serves green", mode_reviewed: "2026-09-01", tag: "platform/Projects" }
      - { method: "GET", path: "/rest/api/3/project/{projectIdOrKey}", area: "projects", tier: 1, status: "green", mode: "derive", tag: "platform/Projects" }
      - { method: "GET", path: "/rest/api/3/project/{projectIdOrKey}/avatars", area: "avatars", tier: 3, status: "green", mode: "derive", mode_reason: "STALE REASON: the 2026-09-09 ruling deferred this row on \"answered with this host's own identicons on hello-16 (refCatalogs, in flight)\" and hello-16 landed it — the 32-row `jira.system-avatars` catalog ships from hello-16 on and app.ts already serves the same rows at /rest/api/3/avatar/{type}/system. `system[]` comes off the catalog and `custom[]` is honestly empty: a custom avatar exists only because somebody uploaded a picture and this universe accepts no writes", mode_reviewed: "2026-09-12", tag: "platform/Project avatars" }
      - { method: "GET", path: "/rest/api/3/project/{projectIdOrKey}/classification-config", area: "project-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "data classification is an Atlassian Guard / Premium feature this site does not have, and Jira answers 403 to a token without the classification scope", mode_reviewed: "2026-09-01", tag: "platform/Project classification levels" }
      - { method: "GET", path: "/rest/api/3/project/{projectIdOrKey}/classification-level/default", area: "project-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "data classification is an Atlassian Guard / Premium feature this site does not have, and Jira answers 403 to a token without the classification scope", mode_reviewed: "2026-09-01", tag: "platform/Project classification levels" }
      - { method: "GET", path: "/rest/api/3/project/{projectIdOrKey}/component", area: "versions-components", tier: 2, status: "green", mode: "derive", mode_reason: "the canon component rows the project's issues already reference", mode_reviewed: "2026-09-01", tag: "platform/Project components" }
      - { method: "GET", path: "/rest/api/3/project/{projectIdOrKey}/components", area: "versions-components", tier: 2, status: "green", mode: "derive", mode_reason: "the canon component rows the project's issues already reference", mode_reviewed: "2026-09-01", tag: "platform/Project components" }
      - { method: "GET", path: "/rest/api/3/project/{projectIdOrKey}/features", area: "platform/project features", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity ProjectSetting", mode_reviewed: "2026-09-01", tag: "platform/Project features", flag: "needs-tier-review" }
      - { method: "GET", path: "/rest/api/3/project/{projectIdOrKey}/properties", area: "properties", tier: 3, status: "green", mode: "empty", mode_reason: "no entity in this Jira site carries an app property - entity properties are written only by Connect/Forge apps through the API and olympus-labs installs none, and this universe accepts no writes; Jira's own answer for a property key that is not set is 404 \"The property key was not found\", and its answer for an entity that carries none is the empty `{\"keys\": []}` this operation declares. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "platform/Project properties" }
      - { method: "GET", path: "/rest/api/3/project/{projectIdOrKey}/properties/{propertyKey}", area: "properties", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no entity in this Jira site carries an app property - entity properties are written only by Connect/Forge apps through the API and olympus-labs installs none, and this universe accepts no writes; Jira's own answer for a property key that is not set is 404 \"The property key was not found\". RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "platform/Project properties" }
      - { method: "GET", path: "/rest/api/3/project/{projectIdOrKey}/role", area: "project-roles", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-10 (hello-16): the role-name → project-role-URL map, over reader.listMembershipRoles() in catalog order. Canon's five MembershipRoleKeys map to Jira's project-role vocabulary in one place (renderer-jira/src/roles.ts). A pre-hello-16 pin answers the named access generation gap (noRoles)", mode_reviewed: "2026-09-10", tag: "platform/Project roles" }
      - { method: "GET", path: "/rest/api/3/project/{projectIdOrKey}/role/{id}", area: "project-roles", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-10 (hello-16): one ProjectRole with THIS project's actors — reader.listMemberships(\"team\", team) filtered to the role and to state=active, because an invitation is not yet an actor. A Jira project is a canonical team here, so the project roster genuinely differs from the site one", mode_reviewed: "2026-09-10", tag: "platform/Project roles" }
      - { method: "GET", path: "/rest/api/3/project/{projectIdOrKey}/roledetails", area: "project-roles", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-10 (hello-16): ProjectRoleDetails over reader.listMembershipRoles() — the catalog without its actors, which is what this operation is for. `currentMember=true` is honoured against reader.listMemberships(\"team\", team) rather than dropped; `admin` is the role's own team:admin rung", mode_reviewed: "2026-09-10", tag: "platform/Project roles" }
      - { method: "GET", path: "/rest/api/3/project/{projectIdOrKey}/statuses", area: "projects", tier: 1, status: "green", mode: "derive", tag: "platform/Projects" }
      - { method: "GET", path: "/rest/api/3/project/{projectIdOrKey}/version", area: "versions-components", tier: 2, status: "green", mode: "derive", mode_reason: "canon releases and milestones, projected onto the project as Jira versions", mode_reviewed: "2026-09-01", tag: "platform/Project versions" }
      - { method: "GET", path: "/rest/api/3/project/{projectIdOrKey}/versions", area: "versions-components", tier: 2, status: "green", mode: "derive", mode_reason: "canon releases and milestones, projected onto the project as Jira versions", mode_reviewed: "2026-09-01", tag: "platform/Project versions" }
      - { method: "GET", path: "/rest/api/3/project/{projectKeyOrId}/issuesecuritylevelscheme", area: "permission-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no issue security scheme exists in this Jira site - canon models no issue-level security and every issue in the one project is visible to every member; the LIST is an honest empty at 200, so this replica is plainly allowed to read schemes and an id over that empty collection can only be Jira's own 404. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "platform/Project permission schemes" }
      - { method: "GET", path: "/rest/api/3/project/{projectKeyOrId}/notificationscheme", area: "projects", tier: 1, status: "planned", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Projects" }
      - { method: "GET", path: "/rest/api/3/project/{projectKeyOrId}/permissionscheme", area: "permission-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Project permission schemes" }
      - { method: "GET", path: "/rest/api/3/project/{projectKeyOrId}/securitylevel", area: "permission-admin", tier: 3, status: "green", mode: "empty", mode_reason: "no issue security scheme exists in this Jira site - canon models no issue-level security and every issue in the one project is visible to every member; Jira creates no issue security scheme with a site and its own answer for a site with none is {\"issueSecuritySchemes\": []} at 200 (an empty page bean on the paged siblings). RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "platform/Project permission schemes" }
      - { method: "GET", path: "/rest/api/3/project/recent", area: "projects", tier: 1, status: "green", mode: "derive", mode_reason: "the projects the authenticated persona belongs to, ordered by their newest issue activity", mode_reviewed: "2026-09-01", tag: "platform/Projects" }
      - { method: "GET", path: "/rest/api/3/project/search", area: "projects", tier: 1, status: "green", mode: "derive", tag: "platform/Projects" }
      - { method: "GET", path: "/rest/api/3/project/type", area: "project-admin", tier: 3, status: "green", mode: "derive", mode_reason: "reader.refCatalog(\"jira.project-types\"); the four keys are the projectTypeKey enum the vendored description declares, so the {projectTypeKey} routes are total over this list. licence: FACTUAL, WITH ONE FIELD OMITTED — key, formattedKey and descriptionI18nKey are functional product identifiers and carry no authorship, but icon is a base64 Adobe-Illustrator SVG, which is Atlassian ARTWORK. ProjectType declares NO required properties in the vendored description, so a response without icon is a legal one and that is what this row will serve. Older pins answer the refCatalogs generation-gap 404 rather than an empty catalogue, which on these rows would be a false claim about the HOST. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", tag: "platform/Project types" }
      - { method: "GET", path: "/rest/api/3/project/type/{projectTypeKey}", area: "project-admin", tier: 3, status: "green", mode: "derive", mode_reason: "reader.refCatalog(\"jira.project-types\") by key; a fifth spelling is Jira's own 404 rather than a coverage miss. licence: FACTUAL, WITH ONE FIELD OMITTED — key, formattedKey and descriptionI18nKey are functional product identifiers and carry no authorship, but icon is a base64 Adobe-Illustrator SVG, which is Atlassian ARTWORK. ProjectType declares NO required properties in the vendored description, so a response without icon is a legal one and that is what this row will serve. Older pins answer the refCatalogs generation-gap 404 rather than an empty catalogue, which on these rows would be a false claim about the HOST. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", tag: "platform/Project types" }
      - { method: "GET", path: "/rest/api/3/project/type/{projectTypeKey}/accessible", area: "project-admin", tier: 3, status: "green", mode: "derive", mode_reason: "reader.refCatalog(\"jira.project-types\") by key, the accessible twin of the by-key row and the same object. licence: FACTUAL, WITH ONE FIELD OMITTED — key, formattedKey and descriptionI18nKey are functional product identifiers and carry no authorship, but icon is a base64 Adobe-Illustrator SVG, which is Atlassian ARTWORK. ProjectType declares NO required properties in the vendored description, so a response without icon is a legal one and that is what this row will serve. Older pins answer the refCatalogs generation-gap 404 rather than an empty catalogue, which on these rows would be a false claim about the HOST. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", tag: "platform/Project types" }
      - { method: "GET", path: "/rest/api/3/project/type/accessible", area: "project-admin", tier: 3, status: "green", mode: "derive", mode_reason: "reader.refCatalog(\"jira.project-types\") - the same four, because this site models neither a licence nor a create permission to narrow them by, and deciding at render time that a type is unavailable would be a fact nothing in canon states. licence: FACTUAL, WITH ONE FIELD OMITTED — key, formattedKey and descriptionI18nKey are functional product identifiers and carry no authorship, but icon is a base64 Adobe-Illustrator SVG, which is Atlassian ARTWORK. ProjectType declares NO required properties in the vendored description, so a response without icon is a legal one and that is what this row will serve. Older pins answer the refCatalogs generation-gap 404 rather than an empty catalogue, which on these rows would be a false claim about the HOST. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", tag: "platform/Project types" }
      - { method: "GET", path: "/rest/api/3/projectCategory", area: "project-admin", tier: 3, status: "green", mode: "empty", mode_reason: "no project category is defined in this Jira site - olympus-labs runs one project and a category is an administrator grouping over many; Jira creates none with a site and its own answer for a site with none is [] at 200. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "platform/Project categories" }
      - { method: "GET", path: "/rest/api/3/projectCategory/{id}", area: "project-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no project category is defined in this Jira site - olympus-labs runs one project and a category is an administrator grouping over many, so no category id resolves and Jira's own 404 for a category that is not found is the whole answer. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "platform/Project categories" }
      - { method: "GET", path: "/rest/api/3/projects/fields", area: "fields", tier: 1, status: "green", mode: "derive", mode_reason: "the field registry in packages/renderer-jira/src/metadata.ts", mode_reviewed: "2026-09-01", tag: "platform/Issue fields" }
      - { method: "GET", path: "/rest/api/3/projectvalidate/key", area: "project-admin", tier: 3, status: "green", mode: "derive", mode_reason: "a pure function over the project keys canon already carries", mode_reviewed: "2026-09-01", tag: "platform/Project key and name validation" }
      - { method: "GET", path: "/rest/api/3/projectvalidate/validProjectKey", area: "project-admin", tier: 3, status: "green", mode: "derive", mode_reason: "a pure function over the project keys canon already carries", mode_reviewed: "2026-09-01", tag: "platform/Project key and name validation" }
      - { method: "GET", path: "/rest/api/3/projectvalidate/validProjectName", area: "project-admin", tier: 3, status: "green", mode: "derive", mode_reason: "a pure function over the project keys canon already carries", mode_reviewed: "2026-09-01", tag: "platform/Project key and name validation" }
      - { method: "GET", path: "/rest/api/3/redact/status/{jobId}", area: "platform/issue redaction", tier: 3, status: "deferred", mode: "refuse", mode_reason: "this universe accepts no writes, so no asynchronous job was ever queued and no task id can resolve — Jira's own 404 for an unknown task is the whole answer", mode_reviewed: "2026-09-01", tag: "platform/Issue redaction", flag: "needs-tier-review" }
      - { method: "GET", path: "/rest/api/3/resolution", area: "metadata", tier: 1, status: "green", mode: "derive", tag: "platform/Issue resolutions" }
      - { method: "GET", path: "/rest/api/3/resolution/{id}", area: "metadata", tier: 1, status: "green", mode: "derive", tag: "platform/Issue resolutions" }
      - { method: "GET", path: "/rest/api/3/resolution/search", area: "metadata", tier: 1, status: "green", mode: "derive", mode_reason: "the status/type/priority/resolution vocabulary the renderer already serves green", mode_reviewed: "2026-09-01", tag: "platform/Issue resolutions" }
      - { method: "GET", path: "/rest/api/3/role", area: "project-roles", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-10 (hello-16): the site-wide role catalog — reader.listMembershipRoles(), each with its DEFAULT actors, which Jira defines as the site-wide assignment a new project starts from and canon holds as reader.listMemberships(\"org\", org). A pre-hello-16 pin answers the named access generation gap (noRoles)", mode_reviewed: "2026-09-10", tag: "platform/Project roles" }
      - { method: "GET", path: "/rest/api/3/role/{id}", area: "project-roles", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-10 (hello-16): the single read off that same catalog, addressed by the id /rest/api/3/role publishes", mode_reviewed: "2026-09-10", tag: "platform/Project roles" }
      - { method: "GET", path: "/rest/api/3/role/{id}/actors", area: "project-roles", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-10 (hello-16): the same ProjectRole document /rest/api/3/role/{id} serves — both carry the role's default actors from reader.listMemberships(\"org\", org), which is what the vendored description says each of them is for", mode_reviewed: "2026-09-10", tag: "platform/Project role actors" }
      - { method: "GET", path: "/rest/api/3/screens", area: "screen-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Screens" }
      - { method: "GET", path: "/rest/api/3/screens/{screenId}/availableFields", area: "screen-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Screens" }
      - { method: "GET", path: "/rest/api/3/screens/{screenId}/tabs", area: "screen-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Screen tabs" }
      - { method: "GET", path: "/rest/api/3/screens/{screenId}/tabs/{tabId}/fields", area: "screen-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Screen tab fields" }
      - { method: "GET", path: "/rest/api/3/screens/tabs", area: "screen-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Screen tabs" }
      - { method: "GET", path: "/rest/api/3/screenscheme", area: "screen-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Screen schemes" }
      - { method: "GET", path: "/rest/api/3/search", area: "search", tier: 1, status: "planned", mode: "refuse", mode_reason: "Atlassian removed GET /rest/api/3/search (CHANGE-2046) and the renderer already answers 410 Gone — the provider's own refusal, mirrored", mode_reviewed: "2026-09-01", tag: "platform/Issue search" }
      - { method: "GET", path: "/rest/api/3/search/jql", area: "search", tier: 1, status: "green", mode: "derive", tag: "platform/Issue search" }
      - { method: "GET", path: "/rest/api/3/securitylevel/{id}", area: "security-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no issue security scheme exists in this Jira site - canon models no issue-level security and every issue in the one project is visible to every member; the LIST is an honest empty at 200, so this replica is plainly allowed to read schemes and an id over that empty collection can only be Jira's own 404. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "platform/Issue security level" }
      - { method: "GET", path: "/rest/api/3/serverInfo", area: "server-info", tier: 1, status: "green", mode: "derive", tag: "platform/Server info" }
      - { method: "GET", path: "/rest/api/3/settings/columns", area: "platform/issue navigator settings", tier: 3, status: "green", mode: "derive", mode_reason: "reader.refCatalog(\"jira.navigator-columns\"); every value is a field /rest/api/3/field already serves. licence: FACTUAL — the response is {label, value} over field ids this host already serves (\"issuekey\", \"summary\" in the vendored description's example). Older pins answer the refCatalogs generation-gap 404 rather than an empty catalogue, which on these rows would be a false claim about the HOST. SERVED 2026-09-09 (hello-16)", mode_reviewed: "2026-09-09", tag: "platform/Issue navigator settings", flag: "needs-tier-review" }
      - { method: "GET", path: "/rest/api/3/status", area: "metadata", tier: 1, status: "green", mode: "derive", tag: "platform/Workflow statuses" }
      - { method: "GET", path: "/rest/api/3/status/{idOrName}", area: "metadata", tier: 1, status: "green", mode: "derive", tag: "platform/Workflow statuses" }
      - { method: "GET", path: "/rest/api/3/statuscategory", area: "metadata", tier: 1, status: "green", mode: "derive", tag: "platform/Workflow status categories" }
      - { method: "GET", path: "/rest/api/3/statuscategory/{idOrKey}", area: "metadata", tier: 1, status: "green", mode: "derive", tag: "platform/Workflow status categories" }
      - { method: "GET", path: "/rest/api/3/statuses", area: "metadata", tier: 1, status: "green", mode: "derive", mode_reason: "the status/type/priority/resolution vocabulary the renderer already serves green", mode_reviewed: "2026-09-01", tag: "platform/Status" }
      - { method: "GET", path: "/rest/api/3/statuses/{statusId}/project/{projectId}/issueTypeUsages", area: "metadata", tier: 1, status: "green", mode: "derive", mode_reason: "the status/type/priority/resolution vocabulary the renderer already serves green", mode_reviewed: "2026-09-01", tag: "platform/Status" }
      - { method: "GET", path: "/rest/api/3/statuses/{statusId}/projectUsages", area: "metadata", tier: 1, status: "green", mode: "derive", mode_reason: "the status/type/priority/resolution vocabulary the renderer already serves green", mode_reviewed: "2026-09-01", tag: "platform/Status" }
      - { method: "GET", path: "/rest/api/3/statuses/{statusId}/workflowUsages", area: "metadata", tier: 1, status: "green", mode: "derive", mode_reason: "the status/type/priority/resolution vocabulary the renderer already serves green", mode_reviewed: "2026-09-01", tag: "platform/Status" }
      - { method: "GET", path: "/rest/api/3/statuses/byNames", area: "metadata", tier: 1, status: "green", mode: "derive", mode_reason: "the status/type/priority/resolution vocabulary the renderer already serves green", mode_reviewed: "2026-09-01", tag: "platform/Status" }
      - { method: "GET", path: "/rest/api/3/statuses/search", area: "metadata", tier: 1, status: "green", mode: "derive", mode_reason: "the status/type/priority/resolution vocabulary the renderer already serves green", mode_reviewed: "2026-09-01", tag: "platform/Status" }
      - { method: "GET", path: "/rest/api/3/task/{taskId}", area: "platform/tasks", tier: 3, status: "deferred", mode: "refuse", mode_reason: "this universe accepts no writes, so no asynchronous job was ever queued and no task id can resolve — Jira's own 404 for an unknown task is the whole answer", mode_reviewed: "2026-09-01", tag: "platform/Tasks", flag: "needs-tier-review" }
      - { method: "GET", path: "/rest/api/3/uiModifications", area: "apps", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no Connect or Forge app is installed on this site; these routes are addressed to an installed app's own scope and Jira answers 401/404 to a caller that is not that app", mode_reviewed: "2026-09-01", tag: "platform/UI modifications (apps)" }
      - { method: "GET", path: "/rest/api/3/universal_avatar/type/{type}/owner/{entityId}", area: "avatars", tier: 3, status: "green", mode: "derive", mode_reason: "STALE REASON: the 2026-09-09 ruling deferred this row on \"answered with this host's own identicons on hello-16 (refCatalogs, in flight)\" and hello-16 landed it — the 32-row `jira.system-avatars` catalog ships from hello-16 on and app.ts already serves the same rows at /rest/api/3/avatar/{type}/system. `system[]` comes off the catalog and `custom[]` is honestly empty: a custom avatar exists only because somebody uploaded a picture and this universe accepts no writes", mode_reviewed: "2026-09-12", tag: "platform/Avatars" }
      - { method: "GET", path: "/rest/api/3/universal_avatar/view/type/{type}", area: "avatars", tier: 3, status: "deferred", mode: "refuse", mode_reason: "these routes return PNG bytes rather than JSON, and the artifact carries no image data for a person or a project", mode_reviewed: "2026-09-01", tag: "platform/Avatars" }
      - { method: "GET", path: "/rest/api/3/universal_avatar/view/type/{type}/avatar/{id}", area: "avatars", tier: 3, status: "deferred", mode: "refuse", mode_reason: "these routes return PNG bytes rather than JSON, and the artifact carries no image data for a person or a project", mode_reviewed: "2026-09-01", tag: "platform/Avatars" }
      - { method: "GET", path: "/rest/api/3/universal_avatar/view/type/{type}/owner/{entityId}", area: "avatars", tier: 3, status: "deferred", mode: "refuse", mode_reason: "these routes return PNG bytes rather than JSON, and the artifact carries no image data for a person or a project", mode_reviewed: "2026-09-01", tag: "platform/Avatars" }
      - { method: "GET", path: "/rest/api/3/user", area: "users", tier: 1, status: "green", mode: "derive", tag: "platform/Users" }
      - { method: "GET", path: "/rest/api/3/user/assignable/multiProjectSearch", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "the person table — the same users /rest/api/3/user already renders", mode_reviewed: "2026-09-01", tag: "platform/User search" }
      - { method: "GET", path: "/rest/api/3/user/assignable/search", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "the person table — the same users /rest/api/3/user already renders", mode_reviewed: "2026-09-01", tag: "platform/User search" }
      - { method: "GET", path: "/rest/api/3/user/bulk", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "the person table — the same users /rest/api/3/user already renders", mode_reviewed: "2026-09-01", tag: "platform/Users" }
      - { method: "GET", path: "/rest/api/3/user/bulk/migration", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "the person table — the same users /rest/api/3/user already renders", mode_reviewed: "2026-09-01", tag: "platform/Users" }
      - { method: "GET", path: "/rest/api/3/user/columns", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "STALE REASON (\"new canon entity UserPreference\"): the 10-row `jira.navigator-columns` catalog ships from hello-16 on and app.ts already serves it at /rest/api/3/settings/columns. Nobody in this site has set columns of their own, and real Jira answers this route with the SITE DEFAULT for a user who has configured none — so the list is the true answer rather than an absence, and conformance asserts the two routes agree row for row", mode_reviewed: "2026-09-12", tag: "platform/Users" }
      - { method: "GET", path: "/rest/api/3/user/email", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "STALE REASON (\"new canon entity PersonCredential\"): `person_credential` ships from hello-16 on and carries 22 `kind=\"email\"` rows over 17 people with an `is_primary` flag; the vendored UnrestrictedUserEmail shape is {accountId,email} and both fields map onto person.id and the primary address — the same column GitHub's `shapeEmail` reads, so the two hosts cannot name different addresses for one canonical person", mode_reviewed: "2026-09-12", tag: "platform/Users" }
      - { method: "GET", path: "/rest/api/3/user/email/bulk", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "STALE REASON (\"new canon entity PersonCredential\"): `person_credential` ships from hello-16 on and carries 22 `kind=\"email\"` rows over 17 people. A DELIBERATE DIVERGENCE FROM THE VENDORED COMPONENT, recorded in renderer-jira/src/app.ts: the document declares the same single `UnrestrictedUserEmail` object for the bulk operation as for the single one while typing its own `accountId` parameter as an ARRAY, so the body served is {\"emails\": [...]}, which real Jira Cloud returns and which validates against the declared component (additionalProperties: true, no required member)", mode_reviewed: "2026-09-12", tag: "platform/Users" }
      - { method: "GET", path: "/rest/api/3/user/groups", area: "users", tier: 1, status: "green", mode: "derive", tag: "platform/Users" }
      - { method: "GET", path: "/rest/api/3/user/permission/search", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "the person table — the same users /rest/api/3/user already renders", mode_reviewed: "2026-09-01", tag: "platform/User search" }
      - { method: "GET", path: "/rest/api/3/user/picker", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "the person table — the same users /rest/api/3/user already renders", mode_reviewed: "2026-09-01", tag: "platform/User search" }
      - { method: "GET", path: "/rest/api/3/user/properties", area: "properties", tier: 3, status: "green", mode: "empty", mode_reason: "no entity in this Jira site carries an app property - entity properties are written only by Connect/Forge apps through the API and olympus-labs installs none, and this universe accepts no writes; Jira's own answer for a property key that is not set is 404 \"The property key was not found\", and its answer for an entity that carries none is the empty `{\"keys\": []}` this operation declares. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "platform/User properties" }
      - { method: "GET", path: "/rest/api/3/user/properties/{propertyKey}", area: "properties", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no entity in this Jira site carries an app property - entity properties are written only by Connect/Forge apps through the API and olympus-labs installs none, and this universe accepts no writes; Jira's own answer for a property key that is not set is 404 \"The property key was not found\". RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "platform/User properties" }
      - { method: "GET", path: "/rest/api/3/user/search", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "the person table — the same users /rest/api/3/user already renders", mode_reviewed: "2026-09-01", tag: "platform/User search" }
      - { method: "GET", path: "/rest/api/3/user/search/query", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "the person table — the same users /rest/api/3/user already renders", mode_reviewed: "2026-09-01", tag: "platform/User search" }
      - { method: "GET", path: "/rest/api/3/user/search/query/key", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "the person table — the same users /rest/api/3/user already renders", mode_reviewed: "2026-09-01", tag: "platform/User search" }
      - { method: "GET", path: "/rest/api/3/user/viewissue/search", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "the person table — the same users /rest/api/3/user already renders", mode_reviewed: "2026-09-01", tag: "platform/User search" }
      - { method: "GET", path: "/rest/api/3/users", area: "users", tier: 1, status: "green", mode: "derive", tag: "platform/Users" }
      - { method: "GET", path: "/rest/api/3/users/search", area: "users", tier: 1, status: "green", mode: "derive", mode_reason: "the person table — the same users /rest/api/3/user already renders", mode_reviewed: "2026-09-01", tag: "platform/Users" }
      - { method: "GET", path: "/rest/api/3/version/{id}", area: "versions-components", tier: 2, status: "green", mode: "derive", mode_reason: "canon releases and milestones, projected onto the project as Jira versions", mode_reviewed: "2026-09-01", tag: "platform/Project versions" }
      - { method: "GET", path: "/rest/api/3/version/{id}/relatedIssueCounts", area: "versions-components", tier: 2, status: "green", mode: "derive", mode_reason: "canon releases and milestones, projected onto the project as Jira versions", mode_reviewed: "2026-09-01", tag: "platform/Project versions" }
      - { method: "GET", path: "/rest/api/3/version/{id}/relatedwork", area: "versions-components", tier: 2, status: "green", mode: "empty", mode_reason: "no issue and no version in olympus-labs carries a remote link - a remote link is an application link to an object in another Atlassian product and this site has no linked Confluence, no linked Bitbucket and no app; Jira's own answer for an issue with none is [] at 200. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "platform/Project versions" }
      - { method: "GET", path: "/rest/api/3/version/{id}/unresolvedIssueCount", area: "versions-components", tier: 2, status: "green", mode: "derive", mode_reason: "canon releases and milestones, projected onto the project as Jira versions", mode_reviewed: "2026-09-01", tag: "platform/Project versions" }
      - { method: "GET", path: "/rest/api/3/webhook", area: "webhooks-config", tier: 2, status: "deferred", mode: "refuse", mode_reason: "Jira restricts the webhook registry to the Connect or OAuth 2.0 app that registered the webhooks - the operation returns only the CALLING APP's webhooks - and this replica is called with no app context, so Jira's own 403 for a non-app caller is the whole answer. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "platform/Webhooks" }
      - { method: "GET", path: "/rest/api/3/webhook/failed", area: "webhooks-config", tier: 2, status: "deferred", mode: "refuse", mode_reason: "Jira restricts the webhook registry to the Connect or OAuth 2.0 app that registered the webhooks - the operation returns only the CALLING APP's webhooks - and this replica is called with no app context, so Jira's own 403 for a non-app caller is the whole answer. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "platform/Webhooks" }
      - { method: "GET", path: "/rest/api/3/workflow/{workflowId}/project/{projectId}/issueTypeUsages", area: "workflow-admin", tier: 3, status: "green", mode: "derive", mode_reason: "the six-state workflow the renderer already serves, plus the issue_transition canon that walks it", mode_reviewed: "2026-09-01", tag: "platform/Workflows" }
      - { method: "GET", path: "/rest/api/3/workflow/{workflowId}/projectUsages", area: "workflow-admin", tier: 3, status: "green", mode: "derive", mode_reason: "the six-state workflow the renderer already serves, plus the issue_transition canon that walks it", mode_reviewed: "2026-09-01", tag: "platform/Workflows" }
      - { method: "GET", path: "/rest/api/3/workflow/{workflowId}/workflowSchemes", area: "workflow-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Workflows" }
      - { method: "GET", path: "/rest/api/3/workflow/rule/config", area: "workflow-admin", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no Connect or Forge app is installed on this site; these routes are addressed to an installed app's own scope and Jira answers 401/404 to a caller that is not that app", mode_reviewed: "2026-09-01", tag: "platform/Workflow transition rules" }
      - { method: "GET", path: "/rest/api/3/workflow/search", area: "workflow-admin", tier: 3, status: "green", mode: "derive", mode_reason: "the six-state workflow the renderer already serves, plus the issue_transition canon that walks it", mode_reviewed: "2026-09-01", tag: "platform/Workflows" }
      - { method: "GET", path: "/rest/api/3/workflows/capabilities", area: "workflow-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "Atlassian's built-in rule catalogue: the static-vendor class ruled 2026-09-09 (#408) — a canon constant + compile-time table on a later generation", mode_reviewed: "2026-09-09", tag: "platform/Workflows" }
      - { method: "GET", path: "/rest/api/3/workflows/defaultEditor", area: "workflow-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity UserPreference", mode_reviewed: "2026-09-01", tag: "platform/Workflows" }
      - { method: "GET", path: "/rest/api/3/workflows/search", area: "workflow-admin", tier: 3, status: "green", mode: "derive", mode_reason: "the six-state workflow the renderer already serves, plus the issue_transition canon that walks it", mode_reviewed: "2026-09-01", tag: "platform/Workflows" }
      - { method: "GET", path: "/rest/api/3/workflowscheme", area: "workflow-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Workflow schemes" }
      - { method: "GET", path: "/rest/api/3/workflowscheme/{id}", area: "workflow-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Workflow schemes" }
      - { method: "GET", path: "/rest/api/3/workflowscheme/{id}/default", area: "workflow-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Workflow schemes" }
      - { method: "GET", path: "/rest/api/3/workflowscheme/{id}/draft", area: "workflow-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Workflow scheme drafts" }
      - { method: "GET", path: "/rest/api/3/workflowscheme/{id}/draft/default", area: "workflow-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Workflow scheme drafts" }
      - { method: "GET", path: "/rest/api/3/workflowscheme/{id}/draft/issuetype/{issueType}", area: "workflow-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Workflow scheme drafts" }
      - { method: "GET", path: "/rest/api/3/workflowscheme/{id}/draft/workflow", area: "workflow-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Workflow scheme drafts" }
      - { method: "GET", path: "/rest/api/3/workflowscheme/{id}/issuetype/{issueType}", area: "workflow-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Workflow schemes" }
      - { method: "GET", path: "/rest/api/3/workflowscheme/{id}/workflow", area: "workflow-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Workflow schemes" }
      - { method: "GET", path: "/rest/api/3/workflowscheme/{workflowSchemeId}/projectUsages", area: "workflow-admin", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Workflow schemes" }
      - { method: "GET", path: "/rest/api/3/workflowscheme/project", area: "platform/workflow scheme project associations", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity Scheme", mode_reviewed: "2026-09-01", tag: "platform/Workflow scheme project associations", flag: "needs-tier-review" }
      - { method: "GET", path: "/rest/api/3/worklog/deleted", area: "worklogs", tier: 2, status: "green", mode: "empty", mode_reason: "nobody in olympus-labs logs time - the generator writes an estimate on an issue (issue.estimate) and never a worklog, so no work log has ever been created, updated or deleted in this universe; Jira's own answer for an issue with none is {\"worklogs\": [], \"total\": 0} at 200 and for the updated/deleted feeds an empty values list with the window's until time. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "platform/Issue worklogs" }
      - { method: "GET", path: "/rest/api/3/worklog/updated", area: "worklogs", tier: 2, status: "green", mode: "empty", mode_reason: "nobody in olympus-labs logs time - the generator writes an estimate on an issue (issue.estimate) and never a worklog, so no work log has ever been created, updated or deleted in this universe; Jira's own answer for an issue with none is {\"worklogs\": [], \"total\": 0} at 200 and for the updated/deleted feeds an empty values list with the window's until time. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "platform/Issue worklogs" }
      - { method: "GET", path: "/rest/atlassian-connect/1/addons/{addonKey}/properties", area: "apps", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no Connect or Forge app is installed on this site; these routes are addressed to an installed app's own scope and Jira answers 401/404 to a caller that is not that app", mode_reviewed: "2026-09-01", tag: "platform/App properties" }
      - { method: "GET", path: "/rest/atlassian-connect/1/addons/{addonKey}/properties/{propertyKey}", area: "apps", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no Connect or Forge app is installed on this site; these routes are addressed to an installed app's own scope and Jira answers 401/404 to a caller that is not that app", mode_reviewed: "2026-09-01", tag: "platform/App properties" }
      - { method: "GET", path: "/rest/atlassian-connect/1/app/module/dynamic", area: "platform/dynamic modules", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no Connect or Forge app is installed on this site; these routes are addressed to an installed app's own scope and Jira answers 401/404 to a caller that is not that app", mode_reviewed: "2026-09-01", tag: "platform/Dynamic modules", flag: "needs-tier-review" }
      - { method: "GET", path: "/rest/atlassian-connect/1/migration/{connectKey}/{jiraIssueFieldsKey}/task", area: "platform/migration of connect modules to forge", tier: 3, status: "deferred", mode: "refuse", mode_reason: "this universe accepts no writes, so no asynchronous job was ever queued and no task id can resolve — Jira's own 404 for an unknown task is the whole answer", mode_reviewed: "2026-09-01", tag: "platform/Migration of Connect modules to Forge", flag: "needs-tier-review" }
      - { method: "GET", path: "/rest/atlassian-connect/1/service-registry", area: "platform/service registry", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no Connect or Forge app is installed on this site; these routes are addressed to an installed app's own scope and Jira answers 401/404 to a caller that is not that app", mode_reviewed: "2026-09-01", tag: "platform/Service Registry", flag: "needs-tier-review" }
      - { method: "GET", path: "/rest/builds/0.1/pipelines/{pipelineId}/builds/{buildNumber}", area: "devinfo", tier: 3, status: "green", mode: "derive", mode_reason: "the workflow_run / job / deployment canon", mode_reviewed: "2026-09-01", tag: "software/Builds" }
      - { method: "GET", path: "/rest/deployments/0.1/pipelines/{pipelineId}/environments/{environmentId}/deployments/{deploymentSequenceNumber}", area: "devinfo", tier: 3, status: "green", mode: "derive", mode_reason: "the workflow_run / job / deployment canon", mode_reviewed: "2026-09-01", tag: "software/Deployments" }
      - { method: "GET", path: "/rest/deployments/0.1/pipelines/{pipelineId}/environments/{environmentId}/deployments/{deploymentSequenceNumber}/gating-status", area: "devinfo", tier: 3, status: "green", mode: "derive", mode_reason: "the deployment's own terminal state in canon — a deployment that ran was allowed through", mode_reviewed: "2026-09-01", tag: "software/Deployments" }
      - { method: "GET", path: "/rest/devinfo/0.10/existsByProperties", area: "devinfo", tier: 3, status: "green", mode: "derive", mode_reason: "the git canon — repositories, branches, commits and pull requests", mode_reviewed: "2026-09-01", tag: "software/Development Information" }
      - { method: "GET", path: "/rest/devinfo/0.10/repository/{repositoryId}", area: "devinfo", tier: 3, status: "green", mode: "derive", mode_reason: "the git canon — repositories, branches, commits and pull requests", mode_reviewed: "2026-09-01", tag: "software/Development Information" }
      - { method: "GET", path: "/rest/devopscomponents/1.0/devopscomponents/{componentId}", area: "devinfo", tier: 3, status: "deferred", mode: "generate", mode_reason: "required tier/componentType/avatarUrl/description have no canon source — generate", mode_reviewed: "2026-09-09", tag: "software/DevOps Components" }
      - { method: "GET", path: "/rest/featureflags/0.1/flag/{featureFlagId}", area: "devinfo", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity FeatureFlag", mode_reviewed: "2026-09-01", tag: "software/Feature Flags" }
      - { method: "GET", path: "/rest/forge/1/app/properties", area: "apps", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no Connect or Forge app is installed on this site; these routes are addressed to an installed app's own scope and Jira answers 401/404 to a caller that is not that app", mode_reviewed: "2026-09-01", tag: "platform/App properties" }
      - { method: "GET", path: "/rest/forge/1/app/properties/{propertyKey}", area: "apps", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no Connect or Forge app is installed on this site; these routes are addressed to an installed app's own scope and Jira answers 401/404 to a caller that is not that app", mode_reviewed: "2026-09-01", tag: "platform/App properties" }
      - { method: "GET", path: "/rest/operations/1.0/incidents/{incidentId}", area: "devinfo", tier: 3, status: "green", mode: "derive", mode_reason: "THE RENDERER JUDGMENT THE 2026-09-09 REASON LEFT OPEN IS TAKEN: Jira Ops' `IncidentData` projects onto canon.Incident with nothing invented. All ten required members have a source — schemaVersion is the document's own enum, id/summary/description/createdDate come off the row, affectedComponents is the one component it broke, status is derived from resolved_epoch, updateSequenceNumber is lastUpdated in millis, and url points at pd.sandboxapis.dev/incidents/{id}, the PagerDuty resource that serves the same row. `associations` names the tracker issue this host itself answers, which is the four-hop cross-check. Gated on the incident domain (hello-12+)", mode_reviewed: "2026-09-12", tag: "software/Operations" }
      - { method: "GET", path: "/rest/operations/1.0/linkedWorkspaces", area: "devinfo", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity DevOpsWorkspace", mode_reviewed: "2026-09-01", tag: "software/Operations" }
      - { method: "GET", path: "/rest/operations/1.0/post-incident-reviews/{reviewId}", area: "devinfo", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity PostIncidentReview — the B1.0 incident domain", mode_reviewed: "2026-09-01", tag: "software/Operations" }
      - { method: "GET", path: "/rest/remotelinks/1.0/remotelink/{remoteLinkId}", area: "devinfo", tier: 3, status: "deferred", mode: "refuse", mode_reason: "no issue and no version in olympus-labs carries a remote link - a remote link is an application link to an object in another Atlassian product and this site has no linked Confluence, no linked Bitbucket and no app, so no link id resolves and Jira's own 404 is the whole answer. RULED by the founder 2026-09-12", mode_reviewed: "2026-09-12", tag: "software/Remote Links" }
      - { method: "GET", path: "/rest/security/1.0/linkedWorkspaces", area: "devinfo", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity DevOpsWorkspace", mode_reviewed: "2026-09-01", tag: "software/Security Information" }
      - { method: "GET", path: "/rest/security/1.0/linkedWorkspaces/{workspaceId}", area: "devinfo", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity DevOpsWorkspace", mode_reviewed: "2026-09-01", tag: "software/Security Information" }
      - { method: "GET", path: "/rest/security/1.0/vulnerability/{vulnerabilityId}", area: "devinfo", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SecurityFinding", mode_reviewed: "2026-09-01", tag: "software/Security Information" }
      - { method: "GET", path: "/rest/software/1.0/board/{boardId}/backlog", area: "boards", tier: 1, status: "green", mode: "derive", mode_reason: "the same board/sprint/epic listings agile/1.0 already serves green", mode_reviewed: "2026-09-01", tag: "software/Board" }
      - { method: "GET", path: "/rest/software/1.0/board/{boardId}/backlog/approximate-count", area: "boards", tier: 1, status: "green", mode: "derive", tag: "software/Board" }
      - { method: "GET", path: "/rest/software/1.0/board/{boardId}/epic/{epicId}/issue", area: "boards", tier: 1, status: "green", mode: "derive", mode_reason: "the same board/sprint/epic listings agile/1.0 already serves green", mode_reviewed: "2026-09-01", tag: "software/Board" }
      - { method: "GET", path: "/rest/software/1.0/board/{boardId}/epic/none/issue", area: "boards", tier: 1, status: "green", mode: "derive", mode_reason: "the same board/sprint/epic listings agile/1.0 already serves green", mode_reviewed: "2026-09-01", tag: "software/Board" }
      - { method: "GET", path: "/rest/software/1.0/board/{boardId}/issue", area: "boards", tier: 1, status: "green", mode: "derive", mode_reason: "the same board/sprint/epic listings agile/1.0 already serves green", mode_reviewed: "2026-09-01", tag: "software/Board" }
      - { method: "GET", path: "/rest/software/1.0/board/{boardId}/issue/approximate-count", area: "boards", tier: 1, status: "green", mode: "derive", tag: "software/Board" }
      - { method: "GET", path: "/rest/software/1.0/board/{boardId}/sprint/{sprintId}/issue", area: "boards", tier: 1, status: "green", mode: "derive", mode_reason: "the same board/sprint/epic listings agile/1.0 already serves green", mode_reviewed: "2026-09-01", tag: "software/Board" }
      - { method: "GET", path: "/rest/software/1.0/epic/{epicIdOrKey}/issue", area: "epics", tier: 1, status: "green", mode: "derive", mode_reason: "the same board/sprint/epic listings agile/1.0 already serves green", mode_reviewed: "2026-09-01", tag: "software/Epic" }
      - { method: "GET", path: "/rest/software/1.0/epic/none/issue", area: "epics", tier: 1, status: "green", mode: "derive", mode_reason: "the same board/sprint/epic listings agile/1.0 already serves green", mode_reviewed: "2026-09-01", tag: "software/Epic" }
      - { method: "GET", path: "/rest/software/1.0/sprint/{sprintId}/issue", area: "sprints", tier: 1, status: "green", mode: "derive", mode_reason: "the same board/sprint/epic listings agile/1.0 already serves green", mode_reviewed: "2026-09-01", tag: "software/Sprint" }
    graphql: [] # no GraphQL API exists for this provider (REST-only)
  linear:
    rest:
    graphql:
      - { entity: "attachments", type: "Attachment", root_field: "attachment", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12: a Linear Attachment is an issue-to-external-URL LINK rather than an uploaded file (the SDL's own `url` description), so the canonical row behind it is canon's `issue.closed_by_pull` edge - the same edge GitHub renders as a pull request's closing reference and GitLab as a merge request's closed issue, now with a fourth rendering and nothing new asserted. NOT canon's `attachment` table, whose only parents are ticket_comment and macro; reading it that way would have made this row a canon widening instead of a rendering. `url` points at gh.sandboxapis.dev, which is exactly what renderer-github prints as the pull's html_url, so the link resolves (invariant #5) - the VCS_ORIGIN precedent renderer-circleci already set. NO generation gate: closed_by_pull is a base-schema column, so an older pin answers FEWER attachments rather than an error. `subtitle` and `bodyData` are null because composing Linear's widget copy would be authoring it", mode_reviewed: "2026-09-12", graphql_only: false }
      - { entity: "comments", type: "Comment", root_field: "comment", tier: 1, status: "green", mode: "derive", graphql_only: false }
      - { entity: "cycles", type: "Cycle", root_field: "cycle", tier: 1, status: "green", mode: "derive", graphql_only: false }
      - { entity: "initiatives", type: "Initiative", root_field: "initiative", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity Initiative", mode_reviewed: "2026-09-01", graphql_only: false }
      - { entity: "issue-history", type: "IssueHistory", tier: 1, status: "green", mode: "derive", graphql_only: false }
      - { entity: "issue-relations", type: "IssueRelation", root_field: "issueRelation", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): IssueRelation is the Linear rendering of canon's issue_link - the same row GitLab serves at /issues/{iid}/links. Linear names both ends outright (issue and relatedIssue) and keeps ONE word for the relationship, so Issue.relations is the rows an issue is the source of and Issue.inverseRelations the rows it is the target of, and neither needs GitLab's direction-dependent vocabulary. The type is mapped to Linear's own set - canon `relates` is Linear `related`, canon `duplicates` is `duplicate` - and the mapping THROWS on a kind with no Linear spelling rather than guessing; `parent` has no member in IssueRelationType at all and carries no row. IssueRelation.type is String! and not the enum, copied verbatim from the pinned SDL. On an artifact without the domain every relation field answers an explicit generation error in `errors` rather than an empty connection, which would assert that nothing in this universe is linked (invariant #4's GraphQL clause)", mode_reviewed: "2026-09-12", graphql_only: false }
      - { entity: "issues", type: "Issue", root_field: "issue", tier: 1, status: "green", mode: "derive", graphql_only: false }
      - { entity: "labels", type: "IssueLabel", root_field: "issueLabel", tier: 1, status: "green", mode: "derive", graphql_only: false }
      - { entity: "orgs", type: "Organization", root_field: "organization", tier: 1, status: "green", mode: "derive", graphql_only: false }
      - { entity: "project-milestones", type: "ProjectMilestone", root_field: "projectMilestone", tier: 2, status: "deferred", mode: "derive", mode_reviewed: "2026-09-01", graphql_only: false }
      - { entity: "project-updates", type: "ProjectUpdate", root_field: "projectUpdate", tier: 2, status: "deferred", mode: "generate", mode_reason: "new canon entity ProjectUpdate", mode_reviewed: "2026-09-01", graphql_only: false }
      - { entity: "projects", type: "Project", root_field: "project", tier: 1, status: "green", mode: "derive", graphql_only: false }
      - { entity: "rate-limit", type: "RateLimitPayload", root_field: "rateLimitStatus", tier: 1, status: "green", mode: "derive", graphql_only: false }
      - { entity: "roadmaps", type: "Roadmap", root_field: "roadmap", tier: 3, status: "deferred", mode: "refuse", mode_reason: "Linear itself deprecated this surface: packages/conformance/specs/linear/graphql/schema.graphql:39381 marks `roadmap` and :39419 marks `roadmaps` with @deprecated(reason: `Roadmaps are deprecated, use initiatives instead.`), so mirroring it would advertise a surface Linear tells clients to stop calling (the ruled vendor-removed precedent, coverage/reviews/2026-09-01-gitlab-modes.md)", mode_reviewed: "2026-09-01", graphql_only: false }
      - { entity: "teams", type: "Team", root_field: "team", tier: 1, status: "green", mode: "derive", graphql_only: false }
      - { entity: "users", type: "User", root_field: "viewer", tier: 1, status: "green", mode: "derive", graphql_only: false }
      - { entity: "workflow-states", type: "WorkflowState", root_field: "workflowState", tier: 1, status: "green", mode: "derive", graphql_only: false }
  anthropic:
    rest:
      - { method: "GET", path: "/v1/organizations/api_keys", area: "api-keys", tier: 1, status: "green", mode: "derive", tag: "api-keys" }
      - { method: "GET", path: "/v1/organizations/api_keys/{api_key_id}", area: "api-keys", tier: 1, status: "green", mode: "derive", tag: "api-keys" }
      - { method: "GET", path: "/v1/organizations/cost_report", area: "usage-report", tier: 1, status: "green", mode: "derive", tag: "usage-report" }
      - { method: "GET", path: "/v1/organizations/invites", area: "invites", tier: 2, status: "green", mode: "empty", mode_reason: "every member of this org already accepted; pending invites are not part of its story (DECISIONS 2026-08-16 [P27])", mode_reviewed: "2026-08-16", tag: "invites" }
      - { method: "GET", path: "/v1/organizations/me", area: "organization", tier: 1, status: "green", mode: "derive", tag: "organization" }
      - { method: "GET", path: "/v1/organizations/usage_report/claude_code", area: "claude-code-analytics", tier: 1, status: "green", mode: "derive", tag: "claude-code-analytics" }
      - { method: "GET", path: "/v1/organizations/usage_report/messages", area: "usage-report", tier: 1, status: "green", mode: "derive", tag: "usage-report" }
      - { method: "GET", path: "/v1/organizations/users", area: "organization", tier: 1, status: "green", mode: "derive", tag: "organization" }
      - { method: "GET", path: "/v1/organizations/users/{user_id}", area: "organization", tier: 1, status: "green", mode: "derive", tag: "organization" }
      - { method: "GET", path: "/v1/organizations/workspaces", area: "workspaces", tier: 1, status: "green", mode: "derive", tag: "workspaces" }
      - { method: "GET", path: "/v1/organizations/workspaces/{workspace_id}", area: "workspaces", tier: 1, status: "green", mode: "derive", tag: "workspaces" }
      - { method: "GET", path: "/v1/organizations/workspaces/{workspace_id}/members", area: "workspaces", tier: 1, status: "green", mode: "derive", tag: "workspaces" }
      - { method: "GET", path: "/v1/organizations/workspaces/{workspace_id}/members/{user_id}", area: "workspaces", tier: 1, status: "green", mode: "derive", tag: "workspaces" }
    graphql: [] # no GraphQL API exists for this provider (REST-only)
  cursor:
    rest:
      - { method: "GET", path: "/analytics/ai-code/changes", area: "ai-code-tracking", tier: 1, status: "green", mode: "derive", tag: "ai-code-tracking" }
      - { method: "GET", path: "/analytics/ai-code/changes.csv", area: "ai-code-tracking", tier: 1, status: "green", mode: "derive", tag: "ai-code-tracking" }
      - { method: "GET", path: "/analytics/ai-code/commits", area: "ai-code-tracking", tier: 1, status: "green", mode: "derive", tag: "ai-code-tracking" }
      - { method: "GET", path: "/analytics/ai-code/commits.csv", area: "ai-code-tracking", tier: 1, status: "green", mode: "derive", tag: "ai-code-tracking" }
      - { method: "GET", path: "/analytics/ai-code/commits/{commitHash}", area: "ai-code-tracking", tier: 1, status: "green", mode: "derive", tag: "ai-code-tracking" }
      - { method: "GET", path: "/analytics/by-user/dau", area: "analytics-by-user", tier: 2, status: "retired", mode: "derive", mode_reason: "served on the pins frozen before the retirement; the live host refuses it (meta.retired_meaning)", tag: "analytics-by-user" }
      - { method: "GET", path: "/analytics/by-user/tabs", area: "analytics-by-user", tier: 2, status: "green", mode: "derive", tag: "analytics-by-user" }
      - { method: "GET", path: "/analytics/team/agent-edits", area: "analytics", tier: 1, status: "green", mode: "derive", tag: "analytics" }
      - { method: "GET", path: "/analytics/team/dau", area: "analytics", tier: 1, status: "green", mode: "derive", tag: "analytics" }
      - { method: "GET", path: "/analytics/team/leaderboard", area: "analytics", tier: 1, status: "green", mode: "derive", tag: "analytics" }
      - { method: "GET", path: "/analytics/team/models", area: "analytics", tier: 1, status: "green", mode: "derive", tag: "analytics" }
      - { method: "GET", path: "/analytics/team/tabs", area: "analytics", tier: 1, status: "green", mode: "derive", tag: "analytics" }
      - { method: "POST", path: "/teams/daily-usage-data", area: "admin-usage", tier: 1, status: "green", mode: "derive", tag: "admin-usage" }
      - { method: "POST", path: "/teams/filtered-usage-events", area: "admin-usage", tier: 1, status: "green", mode: "derive", tag: "admin-usage" }
      - { method: "GET", path: "/teams/members", area: "admin", tier: 1, status: "green", mode: "derive", tag: "admin" }
      - { method: "POST", path: "/teams/spend", area: "admin-usage", tier: 1, status: "green", mode: "derive", tag: "admin-usage" }
      - { method: "GET", path: "/v1/agents", area: "cloud-agents", tier: 2, status: "green", mode: "derive", tag: "cloud-agents" }
      - { method: "GET", path: "/v1/agents/{id}", area: "cloud-agents", tier: 2, status: "green", mode: "derive", tag: "cloud-agents" }
      - { method: "GET", path: "/v1/me", area: "cloud-agents", tier: 2, status: "green", mode: "derive", tag: "cloud-agents" }
      - { method: "GET", path: "/v1/models", area: "cloud-agents", tier: 2, status: "green", mode: "derive", tag: "cloud-agents" }
      - { method: "GET", path: "/v1/repositories", area: "cloud-agents", tier: 2, status: "green", mode: "derive", tag: "cloud-agents" }
    graphql: [] # no GraphQL API exists for this provider (REST-only)
  devin:
    rest:
      - { method: "GET", path: "/v3/enterprise/audit-logs", area: "audit-logs", tier: 3, status: "deferred", mode: "generate", mode_reason: "A WIDENING, NOT A BUILD: canon.AdminAuditEvent exists (packages/canon/src/support-desk.ts:690) and its own doc comment calls it \"GENERIC by construction\". The action vocabulary (AuditAction, :602), the change vocabulary (AuditChangeSlot, :633), the target vocabulary (AuditTargetKind, :611) and the RFC 5737 source-address rule (AuditSourceBlock, :652) all shipped, and Zendesk serves the table today (reader.listAuditEvents(), ruled 2026-09-07). TWO things are missing and neither is the entity: git-host members on AuditTargetKind, and a generation that WRITES personActor — the field is declared for exactly this wave and \"this generation writes none\" (:695-697)", mode_reviewed: "2026-09-09", tag: "audit_logs" }
      - { method: "GET", path: "/v3/enterprise/code-scans/findings", area: "code-scans", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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", mode_reviewed: "2026-09-01", tag: "code-scans" }
      - { method: "GET", path: "/v3/enterprise/code-scans/metrics", area: "code-scans", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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", mode_reviewed: "2026-09-01", tag: "code-scans" }
      - { method: "GET", path: "/v3/enterprise/code-scans/profiles", area: "code-scans", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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", mode_reviewed: "2026-09-01", tag: "code-scans" }
      - { method: "GET", path: "/v3/enterprise/code-scans/profiles/{profile_id}", area: "code-scans", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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", mode_reviewed: "2026-09-01", tag: "code-scans" }
      - { method: "GET", path: "/v3/enterprise/code-scans/scans", area: "code-scans", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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", mode_reviewed: "2026-09-01", tag: "code-scans" }
      - { method: "GET", path: "/v3/enterprise/consumption/acu-limits/devin", area: "consumption-limits", tier: 2, status: "green", mode: "empty", mode_reason: "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])", mode_reviewed: "2026-09-02", tag: "acu-limits" }
      - { method: "GET", path: "/v3/enterprise/consumption/cycles", area: "consumption", tier: 1, status: "green", mode: "derive", tag: "consumption" }
      - { method: "GET", path: "/v3/enterprise/consumption/daily", area: "consumption", tier: 1, status: "green", mode: "derive", tag: "consumption" }
      - { method: "GET", path: "/v3/enterprise/consumption/daily/organizations/{org_id}", area: "consumption", tier: 1, status: "green", mode: "derive", tag: "consumption" }
      - { method: "GET", path: "/v3/enterprise/consumption/daily/service-users/{service_user_id}", area: "consumption", tier: 1, status: "planned", mode: "refuse", mode_reason: "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])", mode_reviewed: "2026-09-01", tag: "consumption" }
      - { method: "GET", path: "/v3/enterprise/consumption/daily/sessions/{session_id}", area: "consumption", tier: 1, status: "green", mode: "derive", tag: "consumption" }
      - { method: "GET", path: "/v3/enterprise/consumption/daily/users/{user_id}", area: "consumption", tier: 1, status: "green", mode: "derive", tag: "consumption" }
      - { method: "GET", path: "/v3/enterprise/git-providers/connections", area: "git-providers", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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", mode_reviewed: "2026-09-01", tag: "git_connections" }
      - { method: "GET", path: "/v3/enterprise/git-providers/connections/{connection_id}/repositories", area: "git-providers", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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", mode_reviewed: "2026-09-01", tag: "git_connections" }
      - { method: "GET", path: "/v3/enterprise/hypervisors", area: "<none>", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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)", mode_reviewed: "2026-09-01", tag: "<none>", flag: "needs-tier-review" }
      - { method: "GET", path: "/v3/enterprise/idp-groups", area: "idp", tier: 3, status: "green", mode: "derive", mode_reason: "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 - all 127 registered pins - 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.", mode_reviewed: "2026-09-12", tag: "idp_groups" }
      - { method: "GET", path: "/v3/enterprise/ip-access-list", area: "network", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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)", mode_reviewed: "2026-09-01", tag: "ip-access-list" }
      - { method: "GET", path: "/v3/enterprise/knowledge/folders", area: "knowledge", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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)", mode_reviewed: "2026-09-01", tag: "notes" }
      - { method: "GET", path: "/v3/enterprise/knowledge/notes", area: "knowledge", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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)", mode_reviewed: "2026-09-01", tag: "notes" }
      - { method: "GET", path: "/v3/enterprise/knowledge/notes/{note_id}", area: "knowledge", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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)", mode_reviewed: "2026-09-01", tag: "notes" }
      - { method: "GET", path: "/v3/enterprise/members/idp-groups", area: "idp", tier: 3, status: "green", mode: "derive", mode_reason: "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 - all 127 registered pins - 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.", mode_reviewed: "2026-09-12", tag: "idp_groups" }
      - { method: "GET", path: "/v3/enterprise/members/idp-groups/{idp_group_name}", area: "idp", tier: 3, status: "green", mode: "derive", mode_reason: "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 - all 127 registered pins - 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.", mode_reviewed: "2026-09-12", tag: "idp_groups" }
      - { method: "GET", path: "/v3/enterprise/members/idp-users", area: "members", tier: 1, status: "green", mode: "empty", mode_reason: "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", mode_reviewed: "2026-09-12", tag: "users" }
      - { method: "GET", path: "/v3/enterprise/members/service-users", area: "service-users", tier: 3, status: "green", mode: "empty", mode_reason: "this universe's only non-human identity is the CI bot and it holds no Devin seat, so the service-user list is empty", mode_reviewed: "2026-09-02", tag: "service_users" }
      - { method: "GET", path: "/v3/enterprise/members/service-users/{service_user_id}", area: "service-users", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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])", mode_reviewed: "2026-09-01", tag: "service_users" }
      - { method: "GET", path: "/v3/enterprise/members/users", area: "members", tier: 1, status: "green", mode: "derive", tag: "users" }
      - { method: "GET", path: "/v3/enterprise/members/users/{user_id}", area: "members", tier: 1, status: "green", mode: "derive", tag: "users" }
      - { method: "GET", path: "/v3/enterprise/metrics/active-users", area: "metrics", tier: 1, status: "green", mode: "derive", tag: "metrics" }
      - { method: "GET", path: "/v3/enterprise/metrics/dau", area: "metrics", tier: 1, status: "green", mode: "derive", tag: "metrics" }
      - { method: "GET", path: "/v3/enterprise/metrics/mau", area: "metrics", tier: 1, status: "green", mode: "derive", tag: "metrics" }
      - { method: "GET", path: "/v3/enterprise/metrics/prs", area: "metrics", tier: 1, status: "green", mode: "derive", tag: "metrics" }
      - { method: "GET", path: "/v3/enterprise/metrics/searches", area: "metrics", tier: 1, status: "green", mode: "derive", tag: "metrics" }
      - { method: "GET", path: "/v3/enterprise/metrics/sessions", area: "metrics", tier: 1, status: "green", mode: "derive", tag: "metrics" }
      - { method: "GET", path: "/v3/enterprise/metrics/sessions-by-category", area: "metrics", tier: 1, status: "green", mode: "derive", tag: "metrics" }
      - { method: "GET", path: "/v3/enterprise/metrics/usage", area: "metrics", tier: 1, status: "green", mode: "derive", tag: "metrics" }
      - { method: "GET", path: "/v3/enterprise/metrics/wau", area: "metrics", tier: 1, status: "green", mode: "derive", tag: "metrics" }
      - { method: "GET", path: "/v3/enterprise/org-group-limits", area: "org-groups", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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)", mode_reviewed: "2026-09-01", tag: "org-groups" }
      - { method: "GET", path: "/v3/enterprise/organizations", area: "organizations", tier: 2, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-12", tag: "organizations" }
      - { method: "GET", path: "/v3/enterprise/organizations/{org_id}", area: "organizations", tier: 2, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-12", tag: "organizations" }
      - { method: "GET", path: "/v3/enterprise/organizations/{org_id}/audit-logs", area: "audit-logs", tier: 3, status: "deferred", mode: "generate", mode_reason: "A WIDENING, NOT A BUILD: canon.AdminAuditEvent exists (packages/canon/src/support-desk.ts:690) and its own doc comment calls it \"GENERIC by construction\". The action vocabulary (AuditAction, :602), the change vocabulary (AuditChangeSlot, :633), the target vocabulary (AuditTargetKind, :611) and the RFC 5737 source-address rule (AuditSourceBlock, :652) all shipped, and Zendesk serves the table today (reader.listAuditEvents(), ruled 2026-09-07). TWO things are missing and neither is the entity: git-host members on AuditTargetKind, and a generation that WRITES personActor — the field is declared for exactly this wave and \"this generation writes none\" (:695-697)", mode_reviewed: "2026-09-09", tag: "audit_logs" }
      - { method: "GET", path: "/v3/enterprise/organizations/{org_id}/git-providers/permissions", area: "git-providers", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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", mode_reviewed: "2026-09-01", tag: "git_permissions" }
      - { method: "GET", path: "/v3/enterprise/organizations/{org_id}/members/idp-groups", area: "idp", tier: 3, status: "green", mode: "derive", mode_reason: "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 - all 127 registered pins - 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.", mode_reviewed: "2026-09-12", tag: "idp_groups" }
      - { method: "GET", path: "/v3/enterprise/organizations/{org_id}/members/idp-groups/{idp_group_name}", area: "idp", tier: 3, status: "green", mode: "derive", mode_reason: "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 - all 127 registered pins - 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.", mode_reviewed: "2026-09-12", tag: "idp_groups" }
      - { method: "GET", path: "/v3/enterprise/organizations/{org_id}/members/idp-users", area: "members", tier: 1, status: "green", mode: "empty", mode_reason: "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", mode_reviewed: "2026-09-12", tag: "users" }
      - { method: "GET", path: "/v3/enterprise/organizations/{org_id}/members/service-users", area: "service-users", tier: 3, status: "green", mode: "empty", mode_reason: "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", mode_reviewed: "2026-09-02", tag: "service_users" }
      - { method: "GET", path: "/v3/enterprise/organizations/{org_id}/members/users", area: "members", tier: 1, status: "green", mode: "derive", tag: "users" }
      - { method: "GET", path: "/v3/enterprise/organizations/{org_id}/metrics/usage", area: "metrics", tier: 1, status: "green", mode: "derive", tag: "metrics" }
      - { method: "GET", path: "/v3/enterprise/organizations/{org_id}/tags", area: "tags", tier: 3, status: "green", mode: "empty", mode_reason: "this org never adopted tagging, which is the same fact the already-ruled session `tags` rows carry (DECISIONS 2026-08-20 [devin])", mode_reviewed: "2026-09-02", tag: "organization-tags" }
      - { method: "GET", path: "/v3/enterprise/organizations/{org_id}/tags/default", area: "tags", tier: 3, status: "green", mode: "empty", mode_reason: "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", mode_reviewed: "2026-09-02", tag: "organization-tags" }
      - { method: "GET", path: "/v3/enterprise/playbooks", area: "playbooks", tier: 3, status: "green", mode: "empty", mode_reason: "nobody here ever wrote a playbook, so the playbook list is empty", mode_reviewed: "2026-09-02", tag: "playbooks" }
      - { method: "GET", path: "/v3/enterprise/playbooks/{playbook_id}", area: "playbooks", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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])", mode_reviewed: "2026-09-01", tag: "playbooks" }
      - { method: "GET", path: "/v3/enterprise/pr-reviews", area: "pr-reviews", tier: 2, status: "deferred", mode: "refuse", mode_reason: "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", mode_reviewed: "2026-09-12", tag: "pr-reviews" }
      - { method: "GET", path: "/v3/enterprise/queue", area: "queue", tier: 2, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-12", tag: "queue" }
      - { method: "GET", path: "/v3/enterprise/roles", area: "roles", tier: 2, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-10", tag: "roles" }
      - { method: "GET", path: "/v3/enterprise/roles/{role_id}", area: "roles", tier: 2, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-10", tag: "roles" }
      - { method: "GET", path: "/v3/enterprise/sessions", area: "sessions", tier: 1, status: "green", mode: "derive", tag: "sessions" }
      - { method: "GET", path: "/v3/enterprise/sessions/{devin_id}", area: "sessions", tier: 1, status: "green", mode: "derive", tag: "sessions" }
      - { method: "GET", path: "/v3/enterprise/sessions/{devin_id}/attachments", area: "sessions", tier: 1, status: "green", mode: "empty", mode_reason: "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", mode_reviewed: "2026-09-12", tag: "sessions" }
      - { method: "GET", path: "/v3/enterprise/sessions/{devin_id}/insights", area: "sessions", tier: 1, status: "planned", mode: "generate", mode_reason: "new canon entity AgentSessionInsight", mode_reviewed: "2026-09-01", tag: "sessions" }
      - { method: "GET", path: "/v3/enterprise/sessions/{devin_id}/messages", area: "sessions", tier: 1, status: "planned", mode: "refuse", mode_reason: "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)", mode_reviewed: "2026-09-01", tag: "sessions" }
      - { method: "GET", path: "/v3/enterprise/sessions/{devin_id}/tags", area: "sessions", tier: 1, status: "green", mode: "empty", mode_reason: "`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])", mode_reviewed: "2026-08-20", tag: "sessions" }
      - { method: "GET", path: "/v3/enterprise/sessions/insights", area: "sessions", tier: 1, status: "planned", mode: "generate", mode_reason: "new canon entity AgentSessionInsight", mode_reviewed: "2026-09-01", tag: "sessions" }
      - { method: "GET", path: "/v3/organizations/{org_id}/attachments/{uuid}/{name}", area: "attachments", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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", mode_reviewed: "2026-09-12", tag: "attachments" }
      - { method: "GET", path: "/v3/organizations/{org_id}/automations", area: "automations", tier: 3, status: "deferred", mode: "refuse", mode_reason: "an automation INSTANCE exists only because somebody configured one, and this universe accepts no writes (invariant #3); the vendor-fixed half of the surface — schemas and templates — is derived instead", mode_reviewed: "2026-09-01", tag: "automations" }
      - { method: "GET", path: "/v3/organizations/{org_id}/automations/{automation_id}", area: "automations", tier: 3, status: "deferred", mode: "refuse", mode_reason: "an automation INSTANCE exists only because somebody configured one, and this universe accepts no writes (invariant #3); the vendor-fixed half of the surface — schemas and templates — is derived instead", mode_reviewed: "2026-09-01", tag: "automations" }
      - { method: "GET", path: "/v3/organizations/{org_id}/automations/schemas", area: "automations", tier: 3, status: "deferred", mode: "derive", mode_reviewed: "2026-09-01", tag: "automations" }
      - { method: "GET", path: "/v3/organizations/{org_id}/automations/templates", area: "automations", tier: 3, status: "deferred", mode: "derive", mode_reviewed: "2026-09-01", tag: "automations" }
      - { method: "GET", path: "/v3/organizations/{org_id}/code-scans/findings", area: "code-scans", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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", mode_reviewed: "2026-09-01", tag: "code-scans" }
      - { method: "GET", path: "/v3/organizations/{org_id}/code-scans/metrics", area: "code-scans", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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", mode_reviewed: "2026-09-01", tag: "code-scans" }
      - { method: "GET", path: "/v3/organizations/{org_id}/code-scans/profiles", area: "code-scans", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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", mode_reviewed: "2026-09-01", tag: "code-scans" }
      - { method: "GET", path: "/v3/organizations/{org_id}/code-scans/profiles/{profile_id}", area: "code-scans", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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", mode_reviewed: "2026-09-01", tag: "code-scans" }
      - { method: "GET", path: "/v3/organizations/{org_id}/code-scans/scans", area: "code-scans", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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", mode_reviewed: "2026-09-01", tag: "code-scans" }
      - { method: "GET", path: "/v3/organizations/{org_id}/consumption/daily", area: "consumption", tier: 1, status: "green", mode: "derive", tag: "consumption" }
      - { method: "GET", path: "/v3/organizations/{org_id}/consumption/daily/service-users/{service_user_id}", area: "consumption", tier: 1, status: "planned", mode: "refuse", mode_reason: "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])", mode_reviewed: "2026-09-01", tag: "consumption" }
      - { method: "GET", path: "/v3/organizations/{org_id}/consumption/daily/sessions/{session_id}", area: "consumption", tier: 1, status: "green", mode: "derive", tag: "consumption" }
      - { method: "GET", path: "/v3/organizations/{org_id}/consumption/daily/users/{user_id}", area: "consumption", tier: 1, status: "green", mode: "derive", tag: "consumption" }
      - { method: "GET", path: "/v3/organizations/{org_id}/knowledge/folders", area: "knowledge", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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)", mode_reviewed: "2026-09-01", tag: "notes" }
      - { method: "GET", path: "/v3/organizations/{org_id}/knowledge/notes", area: "knowledge", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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)", mode_reviewed: "2026-09-01", tag: "notes" }
      - { method: "GET", path: "/v3/organizations/{org_id}/knowledge/notes/{note_id}", area: "knowledge", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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)", mode_reviewed: "2026-09-01", tag: "notes" }
      - { method: "GET", path: "/v3/organizations/{org_id}/metrics/active-users", area: "metrics", tier: 1, status: "green", mode: "derive", tag: "metrics" }
      - { method: "GET", path: "/v3/organizations/{org_id}/metrics/dau", area: "metrics", tier: 1, status: "green", mode: "derive", tag: "metrics" }
      - { method: "GET", path: "/v3/organizations/{org_id}/metrics/mau", area: "metrics", tier: 1, status: "green", mode: "derive", tag: "metrics" }
      - { method: "GET", path: "/v3/organizations/{org_id}/metrics/prs", area: "metrics", tier: 1, status: "green", mode: "derive", tag: "metrics" }
      - { method: "GET", path: "/v3/organizations/{org_id}/metrics/searches", area: "metrics", tier: 1, status: "green", mode: "derive", tag: "metrics" }
      - { method: "GET", path: "/v3/organizations/{org_id}/metrics/sessions", area: "metrics", tier: 1, status: "green", mode: "derive", tag: "metrics" }
      - { method: "GET", path: "/v3/organizations/{org_id}/metrics/usage", area: "metrics", tier: 1, status: "green", mode: "derive", tag: "metrics" }
      - { method: "GET", path: "/v3/organizations/{org_id}/metrics/wau", area: "metrics", tier: 1, status: "green", mode: "derive", tag: "metrics" }
      - { method: "GET", path: "/v3/organizations/{org_id}/playbooks", area: "playbooks", tier: 3, status: "green", mode: "empty", mode_reason: "the org-scoped playbook twin: nobody here ever wrote a playbook, so the playbook list is empty", mode_reviewed: "2026-09-02", tag: "playbooks" }
      - { method: "GET", path: "/v3/organizations/{org_id}/playbooks/{playbook_id}", area: "playbooks", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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])", mode_reviewed: "2026-09-01", tag: "playbooks" }
      - { method: "GET", path: "/v3/organizations/{org_id}/pr-reviews", area: "pr-reviews", tier: 2, status: "deferred", mode: "refuse", mode_reason: "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", mode_reviewed: "2026-09-12", tag: "pr-reviews" }
      - { method: "GET", path: "/v3/organizations/{org_id}/schedules", area: "schedules", tier: 3, status: "deferred", mode: "refuse", mode_reason: "a schedule exists only because somebody created one, and this universe accepts no writes (invariant #3) — nobody here scheduled a recurring Devin run", mode_reviewed: "2026-09-01", tag: "schedules" }
      - { method: "GET", path: "/v3/organizations/{org_id}/schedules/{schedule_id}", area: "schedules", tier: 3, status: "deferred", mode: "refuse", mode_reason: "a schedule exists only because somebody created one, and this universe accepts no writes (invariant #3) — nobody here scheduled a recurring Devin run", mode_reviewed: "2026-09-01", tag: "schedules" }
      - { method: "GET", path: "/v3/organizations/{org_id}/secrets", area: "secrets", tier: 3, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-12", tag: "secrets" }
      - { method: "GET", path: "/v3/organizations/{org_id}/sessions", area: "sessions", tier: 1, status: "green", mode: "derive", tag: "sessions" }
      - { method: "GET", path: "/v3/organizations/{org_id}/sessions/{devin_id}", area: "sessions", tier: 1, status: "green", mode: "derive", tag: "sessions" }
      - { method: "GET", path: "/v3/organizations/{org_id}/sessions/{devin_id}/attachments", area: "sessions", tier: 1, status: "green", mode: "empty", mode_reason: "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", mode_reviewed: "2026-09-12", tag: "sessions" }
      - { method: "GET", path: "/v3/organizations/{org_id}/sessions/{devin_id}/insights", area: "sessions", tier: 1, status: "planned", mode: "generate", mode_reason: "new canon entity AgentSessionInsight", mode_reviewed: "2026-09-01", tag: "sessions" }
      - { method: "GET", path: "/v3/organizations/{org_id}/sessions/{devin_id}/messages", area: "sessions", tier: 1, status: "planned", mode: "refuse", mode_reason: "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)", mode_reviewed: "2026-09-01", tag: "sessions" }
      - { method: "GET", path: "/v3/organizations/{org_id}/sessions/{devin_id}/tags", area: "sessions", tier: 1, status: "green", mode: "empty", mode_reason: "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])", mode_reviewed: "2026-08-20", tag: "sessions" }
      - { method: "GET", path: "/v3/organizations/{org_id}/sessions/insights", area: "sessions", tier: 1, status: "planned", mode: "generate", mode_reason: "new canon entity AgentSessionInsight", mode_reviewed: "2026-09-01", tag: "sessions" }
      - { method: "GET", path: "/v3/self", area: "self", tier: 2, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-12", tag: "self" }
      - { method: "GET", path: "/v3beta1/enterprise/guardrail-violations", area: "guardrails", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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", mode_reviewed: "2026-09-01", tag: "guardrail_violations" }
      - { method: "GET", path: "/v3beta1/enterprise/organizations/{org_id}/guardrail-violations", area: "guardrails", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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", mode_reviewed: "2026-09-01", tag: "guardrail_violations" }
      - { method: "GET", path: "/v3beta1/enterprise/service-users/{service_user_id}/api-keys", area: "service-users", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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])", mode_reviewed: "2026-09-01", tag: "service_user_api_keys" }
      - { method: "GET", path: "/v3beta1/enterprise/snapshot-setup/blueprints", area: "snapshot-setup", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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", mode_reviewed: "2026-09-01", tag: "snapshot_setup" }
      - { method: "GET", path: "/v3beta1/enterprise/snapshot-setup/blueprints/{blueprint_id}", area: "snapshot-setup", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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", mode_reviewed: "2026-09-01", tag: "snapshot_setup" }
      - { method: "GET", path: "/v3beta1/enterprise/snapshot-setup/blueprints/{blueprint_id}/contents", area: "snapshot-setup", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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", mode_reviewed: "2026-09-01", tag: "snapshot_setup" }
      - { method: "GET", path: "/v3beta1/enterprise/snapshot-setup/blueprints/{blueprint_id}/files", area: "snapshot-setup", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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", mode_reviewed: "2026-09-01", tag: "snapshot_setup" }
      - { method: "GET", path: "/v3beta1/organizations/{org_id}/members/idp-users", area: "members", tier: 1, status: "green", mode: "empty", mode_reason: "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", mode_reviewed: "2026-09-12", tag: "users" }
      - { method: "GET", path: "/v3beta1/organizations/{org_id}/members/users", area: "members", tier: 1, status: "green", mode: "derive", tag: "users" }
      - { method: "GET", path: "/v3beta1/organizations/{org_id}/members/users/{user_id}", area: "members", tier: 1, status: "green", mode: "derive", tag: "users" }
      - { method: "GET", path: "/v3beta1/organizations/{org_id}/repositories", area: "repositories", tier: 3, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-12", tag: "repositories" }
      - { method: "GET", path: "/v3beta1/organizations/{org_id}/repositories/{repository_path}/indexing", area: "repositories", tier: 3, status: "deferred", mode: "derive", mode_reviewed: "2026-09-01", tag: "repositories" }
      - { method: "GET", path: "/v3beta1/organizations/{org_id}/repositories/indexing", area: "repositories", tier: 3, status: "green", mode: "derive", mode_reason: "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", mode_reviewed: "2026-09-12", tag: "repositories" }
      - { method: "GET", path: "/v3beta1/organizations/{org_id}/snapshot-setup/blueprints", area: "snapshot-setup", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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", mode_reviewed: "2026-09-01", tag: "snapshot_setup" }
      - { method: "GET", path: "/v3beta1/organizations/{org_id}/snapshot-setup/blueprints/{blueprint_id}", area: "snapshot-setup", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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", mode_reviewed: "2026-09-01", tag: "snapshot_setup" }
      - { method: "GET", path: "/v3beta1/organizations/{org_id}/snapshot-setup/blueprints/{blueprint_id}/contents", area: "snapshot-setup", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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", mode_reviewed: "2026-09-01", tag: "snapshot_setup" }
      - { method: "GET", path: "/v3beta1/organizations/{org_id}/snapshot-setup/blueprints/{blueprint_id}/files", area: "snapshot-setup", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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", mode_reviewed: "2026-09-01", tag: "snapshot_setup" }
      - { method: "GET", path: "/v3beta1/organizations/{org_id}/snapshot-setup/builds", area: "snapshot-setup", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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", mode_reviewed: "2026-09-01", tag: "snapshot_setup" }
      - { method: "GET", path: "/v3beta1/organizations/{org_id}/snapshot-setup/builds/{build_id}", area: "snapshot-setup", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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", mode_reviewed: "2026-09-01", tag: "snapshot_setup" }
      - { method: "GET", path: "/v3beta1/organizations/{org_id}/snapshot-setup/builds/{build_id}/logs", area: "snapshot-setup", tier: 3, status: "deferred", mode: "refuse", mode_reason: "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", mode_reviewed: "2026-09-01", tag: "snapshot_setup" }
    graphql: [] # no GraphQL API exists for this provider (REST-only)
  openai:
    rest:
      - { method: "GET", path: "/assistants", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Assistants" }
      - { method: "GET", path: "/assistants/{assistant_id}", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Assistants" }
      - { method: "GET", path: "/audio/voice_consents", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Audio" }
      - { method: "GET", path: "/audio/voice_consents/{consent_id}", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Audio" }
      - { method: "GET", path: "/batches", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Batch" }
      - { method: "GET", path: "/batches/{batch_id}", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Batch" }
      - { method: "GET", path: "/chat/completions", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Chat" }
      - { method: "GET", path: "/chat/completions/{completion_id}", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Chat" }
      - { method: "GET", path: "/chat/completions/{completion_id}/messages", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Chat" }
      - { method: "GET", path: "/chatkit/threads", area: "<none>", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the same inference plane as the tagged platform rows — chatkit threads and code-interpreter containers only read as separate here because the spec leaves their tag empty; an OpenAI admin key gets 401 invalid_api_key for them too", mode_reviewed: "2026-09-01", tag: "<none>", flag: "needs-tier-review" }
      - { method: "GET", path: "/chatkit/threads/{thread_id}", area: "<none>", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the same inference plane as the tagged platform rows — chatkit threads and code-interpreter containers only read as separate here because the spec leaves their tag empty; an OpenAI admin key gets 401 invalid_api_key for them too", mode_reviewed: "2026-09-01", tag: "<none>", flag: "needs-tier-review" }
      - { method: "GET", path: "/chatkit/threads/{thread_id}/items", area: "<none>", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the same inference plane as the tagged platform rows — chatkit threads and code-interpreter containers only read as separate here because the spec leaves their tag empty; an OpenAI admin key gets 401 invalid_api_key for them too", mode_reviewed: "2026-09-01", tag: "<none>", flag: "needs-tier-review" }
      - { method: "GET", path: "/containers", area: "<none>", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the same inference plane as the tagged platform rows — chatkit threads and code-interpreter containers only read as separate here because the spec leaves their tag empty; an OpenAI admin key gets 401 invalid_api_key for them too", mode_reviewed: "2026-09-01", tag: "<none>", flag: "needs-tier-review" }
      - { method: "GET", path: "/containers/{container_id}", area: "<none>", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the same inference plane as the tagged platform rows — chatkit threads and code-interpreter containers only read as separate here because the spec leaves their tag empty; an OpenAI admin key gets 401 invalid_api_key for them too", mode_reviewed: "2026-09-01", tag: "<none>", flag: "needs-tier-review" }
      - { method: "GET", path: "/containers/{container_id}/files", area: "<none>", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the same inference plane as the tagged platform rows — chatkit threads and code-interpreter containers only read as separate here because the spec leaves their tag empty; an OpenAI admin key gets 401 invalid_api_key for them too", mode_reviewed: "2026-09-01", tag: "<none>", flag: "needs-tier-review" }
      - { method: "GET", path: "/containers/{container_id}/files/{file_id}", area: "<none>", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the same inference plane as the tagged platform rows — chatkit threads and code-interpreter containers only read as separate here because the spec leaves their tag empty; an OpenAI admin key gets 401 invalid_api_key for them too", mode_reviewed: "2026-09-01", tag: "<none>", flag: "needs-tier-review" }
      - { method: "GET", path: "/containers/{container_id}/files/{file_id}/content", area: "<none>", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the same inference plane as the tagged platform rows — chatkit threads and code-interpreter containers only read as separate here because the spec leaves their tag empty; an OpenAI admin key gets 401 invalid_api_key for them too", mode_reviewed: "2026-09-01", tag: "<none>", flag: "needs-tier-review" }
      - { method: "GET", path: "/conversations/{conversation_id}", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Conversations" }
      - { method: "GET", path: "/conversations/{conversation_id}/items", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Conversations" }
      - { method: "GET", path: "/conversations/{conversation_id}/items/{item_id}", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Conversations" }
      - { method: "GET", path: "/evals", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Evals" }
      - { method: "GET", path: "/evals/{eval_id}", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Evals" }
      - { method: "GET", path: "/evals/{eval_id}/runs", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Evals" }
      - { method: "GET", path: "/evals/{eval_id}/runs/{run_id}", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Evals" }
      - { method: "GET", path: "/evals/{eval_id}/runs/{run_id}/output_items", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Evals" }
      - { method: "GET", path: "/evals/{eval_id}/runs/{run_id}/output_items/{output_item_id}", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Evals" }
      - { method: "GET", path: "/files", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Files" }
      - { method: "GET", path: "/files/{file_id}", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Files" }
      - { method: "GET", path: "/files/{file_id}/content", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Files" }
      - { method: "GET", path: "/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Fine-tuning" }
      - { method: "GET", path: "/fine_tuning/jobs", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Fine-tuning" }
      - { method: "GET", path: "/fine_tuning/jobs/{fine_tuning_job_id}", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Fine-tuning" }
      - { method: "GET", path: "/fine_tuning/jobs/{fine_tuning_job_id}/checkpoints", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Fine-tuning" }
      - { method: "GET", path: "/fine_tuning/jobs/{fine_tuning_job_id}/events", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Fine-tuning" }
      - { method: "GET", path: "/models", area: "models", tier: 1, status: "green", mode: "derive", tag: "Models" }
      - { method: "GET", path: "/models/{model}", area: "models", tier: 1, status: "green", mode: "derive", tag: "Models" }
      - { method: "GET", path: "/organization/admin_api_keys", area: "admin-keys", tier: 1, status: "green", mode: "derive", tag: "<none>" }
      - { method: "GET", path: "/organization/admin_api_keys/{key_id}", area: "admin-keys", tier: 1, status: "green", mode: "derive", tag: "<none>" }
      - { method: "GET", path: "/organization/audit_logs", area: "audit-logs", tier: 2, status: "deferred", mode: "generate", mode_reason: "A WIDENING, NOT A BUILD: canon.AdminAuditEvent exists (packages/canon/src/support-desk.ts:690) and its own doc comment calls it \"GENERIC by construction\". The action vocabulary (AuditAction, :602), the change vocabulary (AuditChangeSlot, :633), the target vocabulary (AuditTargetKind, :611) and the RFC 5737 source-address rule (AuditSourceBlock, :652) all shipped, and Zendesk serves the table today (reader.listAuditEvents(), ruled 2026-09-07). TWO things are missing and neither is the entity: git-host members on AuditTargetKind, and a generation that WRITES personActor — the field is declared for exactly this wave and \"this generation writes none\" (:695-697)", mode_reviewed: "2026-09-09", tag: "Audit Logs" }
      - { method: "GET", path: "/organization/certificates", area: "certificates", tier: 3, status: "green", mode: "empty", mode_reason: "OpenAI answers {\"data\": []} to an admin key for the org certificate list when no mTLS certificate has been uploaded, and this org uploaded none — refusing would be false to the provider", mode_reviewed: "2026-09-02", tag: "Certificates" }
      - { method: "GET", path: "/organization/certificates/{certificate_id}", area: "certificates", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the id half of the certificate pair: this org uploaded no mTLS certificate, so no certificate id can resolve and OpenAI's own 404 is the only possible answer (the by-id shape ruled in DECISIONS 2026-09-01 [coverage/A0] for the invite and service-account rows)", mode_reviewed: "2026-09-01", tag: "Certificates" }
      - { method: "GET", path: "/organization/costs", area: "usage", tier: 1, status: "green", mode: "derive", tag: "Usage" }
      - { method: "GET", path: "/organization/data_retention", area: "data-retention", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity RetentionPolicy", mode_reviewed: "2026-09-01", tag: "Data retention" }
      - { method: "GET", path: "/organization/groups", area: "groups", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-10 (hello-15): canon's IdentityGroup — reader.listIdentityGroups(org) (reader.ts:2472) — in the vendored GroupListResource envelope. A GROUP IS NOT A TEAM and this reads neither a team nor a roster: the generator builds each group out of an access fact canon already records (everyone who writes code, everyone who has reviewed something, everyone who may cut a release, the machine accounts) and the canon suite asserts no group has exactly a team's membership, which groups.test.ts re-asserts over the served rows. `is_scim_managed` is the FEDERATION's fact, read off IdentityProviderConfig.scim_enabled, so every group this provider asserts reports the same value. `group_type` is `group` and never `tenant_group`: a tenant group belongs to an OpenAI enterprise tenant standing above the organization, and these are asserted by the organization's own provider. The id is openaiId(\"group_\", \"idgroup-00N\") — the same fnv-1a derivation user-/proj_/key_ ride, so it is a pure function of the canonical id rather than a counter over an iteration order. Older pins answer the noIdentityGroups generation-gap 404 naming openai-2020-10-g10, never an empty list", mode_reviewed: "2026-09-10", tag: "Groups" }
      - { method: "GET", path: "/organization/groups/{group_id}", area: "groups", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-10 (hello-15): the same IdentityGroup by id, byte-identical to the row the list publishes — conformance asserts every group both ways. GroupResponse carries NO `object` field and spells the flag `is_scim_managed`; the document's `Group` schema (the summary embedded in a role assignment) carries `object: \"group\"` and `scim_managed` instead, and these two operations return GroupResponse. A canonical `idgroup-00N` does NOT address a group here, which conformance asserts too", mode_reviewed: "2026-09-10", tag: "Groups" }
      - { method: "GET", path: "/organization/groups/{group_id}/roles", area: "groups", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): the ORGANIZATION role an identity group holds, from the `scope_kind = 'group'` membership hello-17's features.grants writes — reader.groupRole(group) — in the vendored RoleListResource envelope. ONE ROW OR NONE, and that is canon's shape rather than a slice taken in the renderer: a group's role is the FLOOR of its members' own authority, because a grant to a group reaches everyone in it and granting more than its least-authorised member already holds would elevate that person through the directory, so canon writes exactly one row per group (decisions/2026-09-11-2304-hello-17-grants.md). The objects are the SAME AssignedRoleDetails under the SAME ids the user assignments publish — one catalog, two kinds of principal — which groups.test.ts asserts directly, because a schema cannot. Paged by the Roles API's own bounds: list-group-role-assignments declares no limit default and no order default, exactly as list-user-role-assignments does not, so both take 0..1000 / default 1000 / order asc from list-roles. hello-16 and every older artifact answer the noGrants generation-gap 404 naming generation hello-17 — never an empty list, which would be a claim about the ORGANIZATION rather than about the snapshot the caller pinned (the 2026-09-02 ruling). FOUNDER RULING 2026-09-10, round 13", mode_reviewed: "2026-09-12", tag: "Group organization role assignments" }
      - { method: "GET", path: "/organization/groups/{group_id}/roles/{role_id}", area: "groups", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (hello-17): the same assignment by id, byte-identical to the row the list publishes — conformance asserts every group both ways. A REAL catalog role this group does not hold misses here too, the way it does for a user one route over: which role is held is the question the route answers, and a group holds exactly one. The by-id half was PROPOSED as a `refuse` on the reading that no role id could ever resolve for a group; hello-17's grant makes exactly one resolve per group, so the proposal is withdrawn rather than ruled and this is a `derive` like its list. FOUNDER RULING 2026-09-10, round 13", mode_reviewed: "2026-09-12", tag: "Group organization role assignments" }
      - { method: "GET", path: "/organization/groups/{group_id}/users", area: "groups", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-10 (hello-15): a group's canonical members (IdentityGroup.members) INTERSECTED with this organization's own roster, in the vendored UserListResource envelope. THE INTERSECTION IS THE JUDGMENT AND IT IS THE ONLY COHERENT ONE: an OpenAI organization user on this replica is a codex seat holder (renderer-openai/src/render.ts members()), canon's group rosters are rosters of PEOPLE, and serving a person with no account here would publish a user id that 404s against /organization/users/{user_id} standing right beside it — invariant #5 broken in one response pair. OpenAI's own question is which USERS are assigned to the group, and a person with no account is not one of its users; the same reading /v3/enterprise/members/service-users takes on Devin. NOTHING IS HIDDEN, because no shape here publishes a member count: GroupResponse is {id, name, created_at, is_scim_managed, group_type} and carries neither a size nor canon's description. Two of the four groups therefore list nobody, which is DATA rather than a mode — the Default project lists no API key for the same kind of reason — and conformance asserts the served set equals the intersection FROM BOTH SIDES, so a widening and a narrowing are both red. `order` defaults to DESC here and asc on every sibling, which is the document's own default. Older pins answer the noIdentityGroups generation gap", mode_reviewed: "2026-09-10", tag: "Group users" }
      - { method: "GET", path: "/organization/groups/{group_id}/users/{user_id}", area: "groups", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-10 (hello-15): the same membership addressed by (group, user), in the vendored GroupMemberUser shape — the list item plus three fields. A real organization user who is NOT in this group misses here too, because group membership is the question this route answers. `picture` is null because nothing in this universe is a profile-picture URL: canon holds identicon bytes for an org and a repo and nothing keyed to a person, and an authored URL would resolve nowhere (invariant #4). `is_service_account` READS person.is_bot rather than being hard-coded, so it follows rather than being asserted; it is false for everyone this route can reach today because canon's only non-human identity is the CI bot and it holds no codex seat. `user_type` is `user` and never `tenant_user`, for the reason group_type is never tenant_group", mode_reviewed: "2026-09-10", tag: "Group users" }
      - { method: "GET", path: "/organization/invites", area: "invites", tier: 1, status: "green", mode: "empty", mode_reason: "every member of this org accepted; no invite is pending (DECISIONS 2026-08-20 [P31/openai])", mode_reviewed: "2026-08-20", tag: "Invites" }
      - { method: "GET", path: "/organization/invites/{invite_id}", area: "invites", tier: 1, status: "planned", mode: "refuse", mode_reason: "the id half of the invites pair: /organization/invites is `empty` because every member already accepted, so no invite id can resolve and OpenAI's own 404 is the only possible answer (DECISIONS 2026-09-01 [coverage/A0]); `derive` was the wrong word for that answer. The refusal suite owns this row: its OPENAI_ENDPOINTS expectMiss entry was removed 2026-09-03 (founder ruling on proposal 2 of coverage/reviews/2026-09-03-openai-refuse-shapes.md) because it made a refuse row read `green`, and a refusal is terminal by mode, never green by status", mode_reviewed: "2026-09-03", tag: "Invites" }
      - { method: "GET", path: "/organization/projects", area: "projects", tier: 1, status: "green", mode: "derive", tag: "Projects" }
      - { method: "GET", path: "/organization/projects/{project_id}", area: "projects", tier: 1, status: "green", mode: "derive", tag: "Projects" }
      - { method: "GET", path: "/organization/projects/{project_id}/api_keys", area: "projects", tier: 1, status: "green", mode: "derive", tag: "Projects" }
      - { method: "GET", path: "/organization/projects/{project_id}/api_keys/{api_key_id}", area: "projects", tier: 1, status: "green", mode: "derive", tag: "Projects" }
      - { method: "GET", path: "/organization/projects/{project_id}/certificates", area: "certificates", tier: 3, status: "green", mode: "empty", mode_reason: "OpenAI answers {\"data\": []} to an admin key for a project certificate list when no mTLS certificate has been uploaded, and this org uploaded none — refusing would be false to the provider", mode_reviewed: "2026-09-02", tag: "Certificates" }
      - { method: "GET", path: "/organization/projects/{project_id}/data_retention", area: "data-retention", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity RetentionPolicy", mode_reviewed: "2026-09-01", tag: "Data retention" }
      - { method: "GET", path: "/organization/projects/{project_id}/groups", area: "groups", tier: 3, status: "green", mode: "empty", mode_reason: "no identity group has access to a project, and no generation of this universe grants one. The vendored summary on list-project-groups is \"Lists the groups that have ACCESS to a project\" and its item, ProjectGroup, is a GRANT object (object + project_id + group_id + group_name + group_type + created_at) rather than a group — so this list can only carry rows canon does not have. hello-17's features.grants writes one `scope_kind = 'group'` membership per identity group, which attaches the group to a ROLE; IdentityGroup itself carries an org, a provider, a name slot, a member list and a creation instant and nothing that names a container, and a project on this host is minted per TEAM holding a codex seat (renderer-openai/src/render.ts projects()) with no group on either side of it. UNGATED BY GENERATION, deliberately: a generation gap would say the caller's snapshot is too old to answer where the true statement is that the answer is the same on every snapshot there is. The project still has to resolve — a ruling about a project nobody has is a typo answered confidently — and the bounds validated are this operation's own (limit 0..100 default 20, order default asc), which differ from every sibling's. FOUNDER RULING 2026-09-11, round 17", mode_reviewed: "2026-09-11", tag: "Project groups" }
      - { method: "GET", path: "/organization/projects/{project_id}/groups/{group_id}", area: "groups", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the id half of the project-groups pair: its list is empty because no identity group has access to a project, so no (project, group) grant can resolve and OpenAI's own 404 is the only possible answer — the certificates/invites shape ruled 2026-09-01. It addresses a ProjectGroup (the grant) and not a Group, so there is nothing for {group_id} to resolve against and a REAL group id misses here exactly as an invented one does, which is the ruling rather than a gap. Parent-guarded (the project resolves first) and ungated by generation, for the reason the list carries. FOUNDER RULING 2026-09-11, round 17", mode_reviewed: "2026-09-11", tag: "Project groups" }
      - { method: "GET", path: "/organization/projects/{project_id}/hosted_tool_permissions", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the vendored document declares security: [{AdminApiKeyAuth: []}] on retrieve-project-hosted-tool-permissions - the SAME scheme as /organization/users, /organization/costs and the sibling /organization/projects/{project_id}/model_permissions this replica serves at 200 - so the sandbox admin key IS the right credential here and a 401 invalid_api_key would contradict the document; this org configures no hosted-tool permission set, so OpenAI's own 404 for an object that does not exist is the answer, the same shape as /organization/certificates/{certificate_id} (founder ruling 2026-09-03 on proposal 1 of coverage/reviews/2026-09-03-openai-refuse-shapes.md, superseding the INFERENCE-plane 401 read that grouped this row by its \"Hosted tools\" tag rather than by its plane)", mode_reviewed: "2026-09-03", tag: "Hosted tools" }
      - { method: "GET", path: "/organization/projects/{project_id}/model_permissions", area: "projects", tier: 1, status: "green", mode: "empty", mode_reason: "an empty DENY list — no model is denied, which is exactly a universe with no restriction evidence; an empty ALLOW list would claim no model may be called, which the usage report disproves (DECISIONS 2026-08-20 [P31/openai])", mode_reviewed: "2026-08-20", tag: "Projects" }
      - { method: "GET", path: "/organization/projects/{project_id}/rate_limits", area: "projects", tier: 1, status: "green", mode: "empty", mode_reason: "these are policy NUMBERS and this org configures no override; any figure printed here would be a placeholder copied off the spec's example, which invariant #4 forbids. The empty list says 'no override configured' (DECISIONS 2026-08-20 [P31/openai])", mode_reviewed: "2026-08-20", tag: "Projects" }
      - { method: "GET", path: "/organization/projects/{project_id}/service_accounts", area: "projects", tier: 1, status: "green", mode: "empty", mode_reason: "the canon's only non-human identity is the CI bot: it holds no codex seat, belongs to no team and produced no OpenAI usage, so nothing here is a project-scoped machine identity (DECISIONS 2026-08-20 [P31/openai])", mode_reviewed: "2026-08-20", tag: "Projects" }
      - { method: "GET", path: "/organization/projects/{project_id}/service_accounts/{service_account_id}", area: "projects", tier: 1, status: "planned", mode: "refuse", mode_reason: "the id half of the service-account pair: /organization/projects/{project_id}/service_accounts is `empty` because the CI bot is not a project-scoped machine identity, so no service-account id can resolve and OpenAI's own 404 is the only possible answer (DECISIONS 2026-09-01 [coverage/A0]). The refusal suite owns this row: its OPENAI_ENDPOINTS expectMiss entry was removed 2026-09-03 (founder ruling on proposal 2 of coverage/reviews/2026-09-03-openai-refuse-shapes.md) because it made a refuse row read `green`, and a refusal is terminal by mode, never green by status", mode_reviewed: "2026-09-03", tag: "Projects" }
      - { method: "GET", path: "/organization/projects/{project_id}/spend_alerts", area: "spend-alerts", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SpendAlert, hung off the Subscription the A15 wave lands", mode_reviewed: "2026-09-01", tag: "Spend alerts" }
      - { method: "GET", path: "/organization/projects/{project_id}/spend_alerts/{alert_id}", area: "spend-alerts", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SpendAlert, hung off the Subscription the A15 wave lands", mode_reviewed: "2026-09-01", tag: "Spend alerts" }
      - { method: "GET", path: "/organization/projects/{project_id}/spend_limit", area: "<none>", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SpendAlert, hung off the Subscription the A15 wave lands", mode_reviewed: "2026-09-01", tag: "<none>", flag: "needs-tier-review" }
      - { method: "GET", path: "/organization/projects/{project_id}/users", area: "projects", tier: 1, status: "green", mode: "derive", tag: "Projects" }
      - { method: "GET", path: "/organization/projects/{project_id}/users/{user_id}", area: "projects", tier: 1, status: "green", mode: "derive", tag: "Projects" }
      - { method: "GET", path: "/organization/roles", area: "roles", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-10 (hello-16): reader.listMembershipRoles() (packages/artifact/src/reader.ts:3042) in the vendored PublicRoleListResource envelope. Five catalog ROWS rather than an enum rendered at request time: `Role.permissions` is REQUIRED, and a permission list composed inside a renderer is a fact invented at serving time. `permissions` stays canon's closed `scope:level` vocabulary, which the schema types `array<string>` with no enum; `resource_type` is `api.organization`, the document's own example for this scope; and `predefined_role` is DERIVED — a role minted at the organization's own creation instant was created by nobody in it, which conformance asserts as a biconditional rather than as the current answer", mode_reviewed: "2026-09-10", tag: "Roles" }
      - { method: "GET", path: "/organization/roles/{role_id}", area: "roles", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-10 (hello-16): the same catalog row by id — reader.listMembershipRoles() (reader.ts:3042) addressed by openaiId(\"role_\", …), byte-identical to the row the catalog serves, which conformance asserts for all five. An id the catalog does not carry is OpenAI's own `Role <id> not found`, never the empty-body coverage miss", mode_reviewed: "2026-09-10", tag: "Roles" }
      - { method: "GET", path: "/organization/spend_alerts", area: "spend-alerts", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SpendAlert, hung off the Subscription the A15 wave lands", mode_reviewed: "2026-09-01", tag: "Spend alerts" }
      - { method: "GET", path: "/organization/spend_alerts/{alert_id}", area: "spend-alerts", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SpendAlert, hung off the Subscription the A15 wave lands", mode_reviewed: "2026-09-01", tag: "Spend alerts" }
      - { method: "GET", path: "/organization/spend_limit", area: "<none>", tier: 3, status: "deferred", mode: "generate", mode_reason: "new canon entity SpendAlert, hung off the Subscription the A15 wave lands", mode_reviewed: "2026-09-01", tag: "<none>", flag: "needs-tier-review" }
      - { method: "GET", path: "/organization/usage/audio_speeches", area: "usage", tier: 1, status: "green", mode: "empty", mode_reason: "this org's OpenAI story is coding: it recorded no speech usage in the window, so the family's page is real, spec-validating and empty (DECISIONS 2026-08-20 [P31/openai])", mode_reviewed: "2026-08-20", tag: "Usage" }
      - { method: "GET", path: "/organization/usage/audio_transcriptions", area: "usage", tier: 1, status: "green", mode: "empty", mode_reason: "this org's OpenAI story is coding: it recorded no transcription usage in the window, so the family's page is real, spec-validating and empty (DECISIONS 2026-08-20 [P31/openai])", mode_reviewed: "2026-08-20", tag: "Usage" }
      - { method: "GET", path: "/organization/usage/code_interpreter_sessions", area: "usage", tier: 1, status: "green", mode: "empty", mode_reason: "this org's OpenAI story is coding: it recorded no code-interpreter usage in the window, so the family's page is real, spec-validating and empty (DECISIONS 2026-08-20 [P31/openai])", mode_reviewed: "2026-08-20", tag: "Usage" }
      - { method: "GET", path: "/organization/usage/completions", area: "usage", tier: 1, status: "green", mode: "derive", tag: "Usage" }
      - { method: "GET", path: "/organization/usage/embeddings", area: "usage", tier: 1, status: "green", mode: "empty", mode_reason: "this org's OpenAI story is coding: it recorded no embedding usage in the window, so the family's page is real, spec-validating and empty (DECISIONS 2026-08-20 [P31/openai])", mode_reviewed: "2026-08-20", tag: "Usage" }
      - { method: "GET", path: "/organization/usage/file_search_calls", area: "usage", tier: 1, status: "green", mode: "empty", mode_reason: "this org's OpenAI story is coding: it recorded no file-search usage in the window, so the family's page is real, spec-validating and empty (DECISIONS 2026-08-20 [P31/openai])", mode_reviewed: "2026-08-20", tag: "Usage" }
      - { method: "GET", path: "/organization/usage/images", area: "usage", tier: 1, status: "green", mode: "empty", mode_reason: "this org's OpenAI story is coding: it recorded no image usage in the window, so the family's page is real, spec-validating and empty (DECISIONS 2026-08-20 [P31/openai])", mode_reviewed: "2026-08-20", tag: "Usage" }
      - { method: "GET", path: "/organization/usage/moderations", area: "usage", tier: 1, status: "green", mode: "empty", mode_reason: "this org's OpenAI story is coding: it recorded no moderation usage in the window, so the family's page is real, spec-validating and empty (DECISIONS 2026-08-20 [P31/openai])", mode_reviewed: "2026-08-20", tag: "Usage" }
      - { method: "GET", path: "/organization/usage/vector_stores", area: "usage", tier: 1, status: "green", mode: "empty", mode_reason: "this org's OpenAI story is coding: it recorded no vector-store usage in the window, so the family's page is real, spec-validating and empty (DECISIONS 2026-08-20 [P31/openai])", mode_reviewed: "2026-08-20", tag: "Usage" }
      - { method: "GET", path: "/organization/usage/web_search_calls", area: "usage", tier: 1, status: "green", mode: "empty", mode_reason: "this org's OpenAI story is coding: it recorded no web-search usage in the window, so the family's page is real, spec-validating and empty (DECISIONS 2026-08-20 [P31/openai])", mode_reviewed: "2026-08-20", tag: "Usage" }
      - { method: "GET", path: "/organization/users", area: "users", tier: 1, status: "green", mode: "derive", tag: "Users" }
      - { method: "GET", path: "/organization/users/{user_id}", area: "users", tier: 1, status: "green", mode: "derive", tag: "Users" }
      - { method: "GET", path: "/organization/users/{user_id}/roles", area: "roles", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-10 (hello-16): the role on this person's ACTIVE organization membership — reader.listMemberships(\"org\", org) (reader.ts:3020) — rendered as the catalog row it names, in the vendored RoleListResource envelope. A pending membership is an invitation and is not an assignment, which is the only place that distinction could have been lost. The four nulls are facts: canon records no edit to a catalog row (`updated_at`), no author for one (`created_by`), and every assignment is held directly rather than inherited (`assignment_sources`)", mode_reviewed: "2026-09-10", tag: "User organization role assignments" }
      - { method: "GET", path: "/organization/users/{user_id}/roles/{role_id}", area: "roles", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-10 (hello-16): the same assignment addressed by (user, role) — reader.listMemberships(\"org\", org) (reader.ts:3020). A REAL catalog role this person does not hold misses here too, because which role you hold is the question this route answers; conformance drives both halves", mode_reviewed: "2026-09-10", tag: "User organization role assignments" }
      - { method: "GET", path: "/projects/{project_id}/groups/{group_id}/roles", area: "groups", tier: 3, status: "deferred", mode: "refuse", mode_reason: "NOT the project-scoped twin of /organization/groups/{group_id}/roles, and the difference is what decides the mode: this one is scoped BY a group's access to a project, and /organization/projects/{project_id}/groups is `empty` because no identity group has that access in any generation (founder ruling 2026-09-11, round 17). So the (project, group) pair never resolves and OpenAI's own 404 is the only possible answer — the same reading /projects/{project_id}/users/{user_id}/roles already takes one route over, where a person who is not in the project misses rather than getting an empty list. hello-17's features.grants attaches a group to an ORGANIZATION role, which /organization/groups/{group_id}/roles serves; it attaches nothing to a container. The refusal names the GROUP and not the role, because the group's access is the first thing that fails and the request never reaches a role. Parent-guarded (the project resolves first) and ungated by generation, for the reason the project-groups pair carries. FOLLOWS FROM FOUNDER RULING 2026-09-11, round 17", mode_reviewed: "2026-09-11", tag: "Project group role assignments" }
      - { method: "GET", path: "/projects/{project_id}/groups/{group_id}/roles/{role_id}", area: "groups", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the id half of the project group-roles pair: its list refuses because no identity group has access to a project, so the (project, group) pair never resolves and no role id under it can either — OpenAI's own 404, naming the group rather than the role for the reason the list gives. Same guard, same ungating, same ruling. FOLLOWS FROM FOUNDER RULING 2026-09-11, round 17", mode_reviewed: "2026-09-11", tag: "Project group role assignments" }
      - { method: "GET", path: "/projects/{project_id}/roles", area: "roles", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-10 (hello-16): the same reader.listMembershipRoles() catalog (reader.ts:3042) at project scope — `resource_type: api.project`, the document's own example for this scope, under ids of its own because OpenAI addresses an organization role and a project role as different objects. Same name, same description, same permissions, same created_at as the organization row, which conformance asserts; an organization role id does NOT address a project role, which it asserts too", mode_reviewed: "2026-09-10", tag: "Roles" }
      - { method: "GET", path: "/projects/{project_id}/roles/{role_id}", area: "roles", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-10 (hello-16): the project catalog row by id — reader.listMembershipRoles() (reader.ts:3042). The project must still resolve, so an unknown {project_id} is OpenAI's own `Project <id> not found` rather than a cheerful empty catalog", mode_reviewed: "2026-09-10", tag: "Roles" }
      - { method: "GET", path: "/projects/{project_id}/users/{user_id}/roles", area: "roles", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-10 (hello-16): the role on this person's membership in the container the PROJECT IS — reader.listMemberships(\"team\", team) for a team project and reader.listMemberships(\"org\", org) for the Default project (reader.ts:3020), since a project here is a team holding a codex seat and Default is the organization's own project. One rule, total over every project this renderer mints, which is why an assignment can never name somebody outside the container; a user who is not in the project misses rather than getting an empty list", mode_reviewed: "2026-09-10", tag: "Project user role assignments" }
      - { method: "GET", path: "/projects/{project_id}/users/{user_id}/roles/{role_id}", area: "roles", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-10 (hello-16): the same project assignment addressed by (project, user, role) — reader.listMemberships over team and org scope (reader.ts:3020). Byte-identical to the row the list serves, and a role the person does not hold in THIS project is OpenAI's own 404", mode_reviewed: "2026-09-10", tag: "Project user role assignments" }
      - { method: "GET", path: "/responses/{response_id}", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Responses" }
      - { method: "GET", path: "/responses/{response_id}?beta=true", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Responses" }
      - { method: "GET", path: "/responses/{response_id}/input_items", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Responses" }
      - { method: "GET", path: "/responses/{response_id}/input_items?beta=true", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Responses" }
      - { method: "GET", path: "/skills", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Skills" }
      - { method: "GET", path: "/skills/{skill_id}", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Skills" }
      - { method: "GET", path: "/skills/{skill_id}/content", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Skills" }
      - { method: "GET", path: "/skills/{skill_id}/versions", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Skills" }
      - { method: "GET", path: "/skills/{skill_id}/versions/{version}", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Skills" }
      - { method: "GET", path: "/skills/{skill_id}/versions/{version}/content", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Skills" }
      - { method: "GET", path: "/threads/{thread_id}", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Assistants" }
      - { method: "GET", path: "/threads/{thread_id}/messages", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Assistants" }
      - { method: "GET", path: "/threads/{thread_id}/messages/{message_id}", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Assistants" }
      - { method: "GET", path: "/threads/{thread_id}/runs", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Assistants" }
      - { method: "GET", path: "/threads/{thread_id}/runs/{run_id}", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Assistants" }
      - { method: "GET", path: "/threads/{thread_id}/runs/{run_id}/steps", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Assistants" }
      - { method: "GET", path: "/threads/{thread_id}/runs/{run_id}/steps/{step_id}", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Assistants" }
      - { method: "GET", path: "/vector_stores", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Vector stores" }
      - { method: "GET", path: "/vector_stores/{vector_store_id}", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Vector stores" }
      - { method: "GET", path: "/vector_stores/{vector_store_id}/file_batches/{batch_id}", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Vector stores" }
      - { method: "GET", path: "/vector_stores/{vector_store_id}/file_batches/{batch_id}/files", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Vector stores" }
      - { method: "GET", path: "/vector_stores/{vector_store_id}/files", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Vector stores" }
      - { method: "GET", path: "/vector_stores/{vector_store_id}/files/{file_id}", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Vector stores" }
      - { method: "GET", path: "/vector_stores/{vector_store_id}/files/{file_id}/content", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Vector stores" }
      - { method: "GET", path: "/videos", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Videos" }
      - { method: "GET", path: "/videos/{video_id}", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Videos" }
      - { method: "GET", path: "/videos/{video_id}/content", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Videos" }
      - { method: "GET", path: "/videos/characters/{character_id}", area: "platform", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface", mode_reviewed: "2026-09-01", tag: "Videos" }
    graphql: [] # no GraphQL API exists for this provider (REST-only)
  chatgpt:
    rest:
      - { method: "GET", path: "/v1/analytics/codex/workspaces/{workspace_id}/code_review_responses", area: "codex-code-review-responses", tier: 1, status: "green", mode: "empty", mode_reason: "the response side of the same fact: with no code reviews, there are no review responses (DECISIONS 2026-08-18 [P32] decision 4)", mode_reviewed: "2026-08-18", tag: "codex_enterprise_code_review_responses" }
      - { method: "GET", path: "/v1/analytics/codex/workspaces/{workspace_id}/code_reviews", area: "codex-code-reviews", tier: 1, status: "green", mode: "empty", mode_reason: "the two-seat Codex trial uses CLI and IDE clients and never enabled the GitHub review integration, so no code review exists to report (DECISIONS 2026-08-18 [P32] decision 4)", mode_reviewed: "2026-08-18", tag: "codex_enterprise_code_reviews" }
      - { method: "GET", path: "/v1/analytics/codex/workspaces/{workspace_id}/usage", area: "codex-usage", tier: 1, status: "green", mode: "derive", tag: "codex_enterprise_usage" }
    graphql: [] # no GraphQL API exists for this provider (REST-only)
  teams:
    rest:
      - { method: "GET", path: "/me", area: "users", tier: 1, status: "green", mode: "derive", tag: "me.user" }
      - { method: "GET", path: "/me/joinedTeams", area: "teams", tier: 1, status: "green", mode: "derive", tag: "me.team" }
      - { method: "GET", path: "/teams", area: "teams", tier: 1, status: "green", mode: "derive", tag: "teams.team" }
      - { method: "GET", path: "/teams/{team-id}", area: "teams", tier: 1, status: "green", mode: "derive", tag: "teams.team" }
      - { method: "GET", path: "/teams/{team-id}/channels", area: "channels", tier: 1, status: "green", mode: "derive", tag: "teams.channel" }
      - { method: "GET", path: "/teams/{team-id}/channels/{channel-id}", area: "channels", tier: 1, status: "green", mode: "derive", tag: "teams.channel" }
      - { method: "GET", path: "/teams/{team-id}/channels/{channel-id}/messages", area: "messages", tier: 1, status: "green", mode: "derive", tag: "teams.channel" }
      - { method: "GET", path: "/teams/{team-id}/channels/{channel-id}/messages/{chatMessage-id}", area: "messages", tier: 1, status: "green", mode: "derive", tag: "teams.channel" }
      - { method: "GET", path: "/teams/{team-id}/channels/{channel-id}/messages/{chatMessage-id}/replies", area: "messages", tier: 1, status: "green", mode: "derive", tag: "teams.channel" }
      - { method: "GET", path: "/teams/{team-id}/members", area: "members", tier: 1, status: "green", mode: "derive", tag: "teams.conversationMember" }
      - { method: "GET", path: "/users", area: "users", tier: 1, status: "green", mode: "derive", tag: "users.user" }
      - { method: "GET", path: "/users/{user-id}", area: "users", tier: 1, status: "green", mode: "derive", tag: "users.user" }
      - { method: "GET", path: "/users/{user-id}/joinedTeams", area: "teams", tier: 1, status: "green", mode: "derive", tag: "users.team" }
    graphql: [] # no GraphQL API exists for this provider (REST-only)
  pagerduty:
    rest:
      - { method: "GET", path: "/{entity_type}/{id}/tags", area: "tags", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Tags" }
      - { method: "GET", path: "/abilities", area: "abilities", tier: 1, status: "green", mode: "derive", mode_reason: "served VERBATIM from a captured response (packages/conformance/specs/pagerduty/captures/abilities.json, sha-pinned in coverage/provider-pins.yaml under pagerduty.captures-file): 53 ability names captured 2026-09-02 from api.pagerduty.com using PagerDuty's PUBLIC developer-docs sample credentials, so the evidence is reproducible by anyone rather than taken on trust. That capture is the exact unblock the 2026-09-01 refusal named. It reaches PagerDuty's DEMO account, which is feature-rich — the operation says an ability depends on 'your pricing plan or account state', so no single list is correct and a captured one beats a chosen one", mode_reviewed: "2026-09-02", tag: "Abilities" }
      - { method: "GET", path: "/abilities/{id}", area: "abilities", tier: 1, status: "green", mode: "derive", mode_reason: "the 204/404 membership test over the same captured list — every one of the 53 answers 204 and anything else takes the document's own NotFound. NOT the 402: that response reads 'Account does not have the abilities to perform the action' and is declared on eighty-five other operations, so it is the product's generic plan gate on an ACTION rather than this operation's membership answer", mode_reviewed: "2026-09-02", tag: "Abilities" }
      - { method: "GET", path: "/addons", area: "addons", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Add-ons" }
      - { method: "GET", path: "/addons/{id}", area: "addons", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Add-ons" }
      - { method: "GET", path: "/alert_grouping_settings", area: "alert-grouping", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Alert Grouping Settings" }
      - { method: "GET", path: "/alert_grouping_settings/{id}", area: "alert-grouping", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Alert Grouping Settings" }
      - { method: "GET", path: "/analytics/raw/incidents/{id}", area: "analytics", tier: 2, status: "green", mode: "derive", mode_reason: "TRUE AGGREGATIONS over the incident's own timeline, not statistics invented at render time: every duration is arithmetic over `Incident.openedOffset`/`acknowledgedOffset`/`resolvedOffset`, every count is over the `Page` rows the policy actually sent, and the business/off/sleep interruption buckets are computed from each page's sent instant on the RESPONDER's own clock (`Person.utcOffsetMin`) at PagerDuty's published boundaries. Six declared fields stay ABSENT because the canon states no fact behind them — `auto_resolved`, `major`, `snoozed_seconds`, `user_defined_effort_seconds` and the two `joined_user_*` — and a flat object of optional integers is exactly where a plausible number would never be caught", mode_reviewed: "2026-09-02", tag: "Analytics" }
      - { method: "GET", path: "/analytics/raw/incidents/{id}/responses", area: "analytics", tier: 2, status: "green", mode: "derive", mode_reason: "one row per `Page`: who was notified, at which rung, when it was sent and when they answered. `responder_type` is read off the rung (0 IS the assignment, above it is the escalation) and `reassigned`/`added_responder` are unreachable because both are writes — a fact about a read-only universe rather than an unwritten branch", mode_reviewed: "2026-09-02", tag: "Analytics" }
      - { method: "GET", path: "/audit/records", area: "audit", tier: 2, status: "deferred", mode: "refuse", mode_reason: "the ONE audit operation the document gates explicitly, in its own words: \"Only admins, account owners, or global API tokens on PagerDuty accounts with the 'Audit Trail' feature can access this endpoint.\" The account-wide trail is both admin-only and plan-gated, and no ability in the captured /abilities response names Audit Trail. The RESOURCE-scoped audit rows carry no such sentence and are classified `generate` below — the split is the document's, not ours", mode_reviewed: "2026-09-02", tag: "Audit" }
      - { method: "GET", path: "/automation_actions/actions", area: "automation", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Automation Actions" }
      - { method: "GET", path: "/automation_actions/actions/{id}", area: "automation", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Automation Actions" }
      - { method: "GET", path: "/automation_actions/actions/{id}/services", area: "automation", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Automation Actions" }
      - { method: "GET", path: "/automation_actions/actions/{id}/services/{service_id}", area: "automation", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Automation Actions" }
      - { method: "GET", path: "/automation_actions/actions/{id}/teams", area: "automation", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Automation Actions" }
      - { method: "GET", path: "/automation_actions/actions/{id}/teams/{team_id}", area: "automation", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Automation Actions" }
      - { method: "GET", path: "/automation_actions/invocations", area: "automation", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Automation Actions" }
      - { method: "GET", path: "/automation_actions/invocations/{id}", area: "automation", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Automation Actions" }
      - { method: "GET", path: "/automation_actions/runners", area: "automation", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Automation Actions" }
      - { method: "GET", path: "/automation_actions/runners/{id}", area: "automation", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Automation Actions" }
      - { method: "GET", path: "/automation_actions/runners/{id}/teams", area: "automation", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Automation Actions" }
      - { method: "GET", path: "/automation_actions/runners/{id}/teams/{team_id}", area: "automation", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Automation Actions" }
      - { method: "GET", path: "/business_services", area: "business-services", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Business Services" }
      - { method: "GET", path: "/business_services/{id}", area: "business-services", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Business Services" }
      - { method: "GET", path: "/business_services/{id}/subscribers", area: "business-services", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Business Services" }
      - { method: "GET", path: "/business_services/{id}/supporting_services/impacts", area: "business-services", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Business Services" }
      - { method: "GET", path: "/business_services/impactors", area: "business-services", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Business Services" }
      - { method: "GET", path: "/business_services/impacts", area: "business-services", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Business Services" }
      - { method: "GET", path: "/business_services/priority_thresholds", area: "business-services", tier: 2, status: "green", mode: "derive", mode_reason: "NULL, and the null is the fact rather than a gap: a global impact threshold is something an admin SETS, setting one is a write, and the document's own example for an account that has not set one is `{\"global_threshold\": null}`. Naming a priority would assert an impact rule this account never configured — and every incident here would then read as impacting business services it has none of", mode_reviewed: "2026-09-02", tag: "Business Services" }
      - { method: "GET", path: "/change_events", area: "change-events", tier: 2, status: "green", mode: "derive", mode_reason: "canon's `Deployment` rows in PagerDuty's own vocabulary — its `related_change_events` operation defines a change event as \"service changes such as deploys, build completion, and configuration changes\", which is the entity the git canon already records: a real commit, to a real environment, by a real person. `custom_details.commit` is the SAME sha every git host serves for that deploy, so a responder can follow one change across providers (invariant #5). `integration`, `routing_key`, `source`, `links` and `images` are omitted because this universe has no inbound integration — the reason the renderer already omits `Service.integrations`. `change_events` is one of the 53 names in the captured /abilities response, so the surface and the ability list agree", mode_reviewed: "2026-09-02", tag: "Change Events" }
      - { method: "GET", path: "/change_events/{id}", area: "change-events", tier: 2, status: "green", mode: "derive", mode_reason: "canon's `Deployment` rows in PagerDuty's own vocabulary — its `related_change_events` operation defines a change event as \"service changes such as deploys, build completion, and configuration changes\", which is the entity the git canon already records: a real commit, to a real environment, by a real person. `custom_details.commit` is the SAME sha every git host serves for that deploy, so a responder can follow one change across providers (invariant #5). `integration`, `routing_key`, `source`, `links` and `images` are omitted because this universe has no inbound integration — the reason the renderer already omits `Service.integrations`. `change_events` is one of the 53 names in the captured /abilities response, so the surface and the ability list agree", mode_reviewed: "2026-09-02", tag: "Change Events" }
      - { method: "GET", path: "/enrichment/event_enrichments", area: "event-orchestration", tier: 3, status: "deferred", mode: "refuse", mode_reason: "PagerDuty's own words on every operation in this family: \"This API is in Early Access and may change at any time. Contact your PagerDuty account team to request access.\" This replica has not requested access and cannot — the gate is a conversation with a vendor, not a plan — so PagerDuty's refusal to an unenrolled account IS the true answer. Serving a Contextual Data Platform schema would additionally assert an integration posture (ServiceNow CMDB sync) that this engineering org has never had", mode_reviewed: "2026-09-02", tag: "Event Enrichments" }
      - { method: "GET", path: "/enrichment/event_enrichments/{id}", area: "event-orchestration", tier: 3, status: "deferred", mode: "refuse", mode_reason: "PagerDuty's own words on every operation in this family: \"This API is in Early Access and may change at any time. Contact your PagerDuty account team to request access.\" This replica has not requested access and cannot — the gate is a conversation with a vendor, not a plan — so PagerDuty's refusal to an unenrolled account IS the true answer. Serving a Contextual Data Platform schema would additionally assert an integration posture (ServiceNow CMDB sync) that this engineering org has never had", mode_reviewed: "2026-09-02", tag: "Event Enrichments" }
      - { method: "GET", path: "/enrichment/event_enrichments/{id}/associations", area: "event-orchestration", tier: 3, status: "deferred", mode: "refuse", mode_reason: "PagerDuty's own words on every operation in this family: \"This API is in Early Access and may change at any time. Contact your PagerDuty account team to request access.\" This replica has not requested access and cannot — the gate is a conversation with a vendor, not a plan — so PagerDuty's refusal to an unenrolled account IS the true answer. Serving a Contextual Data Platform schema would additionally assert an integration posture (ServiceNow CMDB sync) that this engineering org has never had", mode_reviewed: "2026-09-02", tag: "Event Enrichments" }
      - { method: "GET", path: "/enrichment/event_enrichments/{id}/rules", area: "event-orchestration", tier: 3, status: "deferred", mode: "refuse", mode_reason: "PagerDuty's own words on every operation in this family: \"This API is in Early Access and may change at any time. Contact your PagerDuty account team to request access.\" This replica has not requested access and cannot — the gate is a conversation with a vendor, not a plan — so PagerDuty's refusal to an unenrolled account IS the true answer. Serving a Contextual Data Platform schema would additionally assert an integration posture (ServiceNow CMDB sync) that this engineering org has never had", mode_reviewed: "2026-09-02", tag: "Event Enrichments" }
      - { method: "GET", path: "/enrichment/event_enrichments/default", area: "event-orchestration", tier: 3, status: "deferred", mode: "refuse", mode_reason: "PagerDuty's own words on every operation in this family: \"This API is in Early Access and may change at any time. Contact your PagerDuty account team to request access.\" This replica has not requested access and cannot — the gate is a conversation with a vendor, not a plan — so PagerDuty's refusal to an unenrolled account IS the true answer. Serving a Contextual Data Platform schema would additionally assert an integration posture (ServiceNow CMDB sync) that this engineering org has never had", mode_reviewed: "2026-09-02", tag: "Event Enrichments" }
      - { method: "GET", path: "/enrichment/integrations/servicenow", area: "event-orchestration", tier: 3, status: "deferred", mode: "refuse", mode_reason: "PagerDuty's own words on every operation in this family: \"This API is in Early Access and may change at any time. Contact your PagerDuty account team to request access.\" This replica has not requested access and cannot — the gate is a conversation with a vendor, not a plan — so PagerDuty's refusal to an unenrolled account IS the true answer. Serving a Contextual Data Platform schema would additionally assert an integration posture (ServiceNow CMDB sync) that this engineering org has never had", mode_reviewed: "2026-09-02", tag: "Enrichment Integrations" }
      - { method: "GET", path: "/enrichment/integrations/servicenow/{integration_id}", area: "event-orchestration", tier: 3, status: "deferred", mode: "refuse", mode_reason: "PagerDuty's own words on every operation in this family: \"This API is in Early Access and may change at any time. Contact your PagerDuty account team to request access.\" This replica has not requested access and cannot — the gate is a conversation with a vendor, not a plan — so PagerDuty's refusal to an unenrolled account IS the true answer. Serving a Contextual Data Platform schema would additionally assert an integration posture (ServiceNow CMDB sync) that this engineering org has never had", mode_reviewed: "2026-09-02", tag: "Enrichment Integrations" }
      - { method: "GET", path: "/enrichment/integrations/servicenow/{integration_id}/tables/{table_id}/test", area: "event-orchestration", tier: 3, status: "deferred", mode: "refuse", mode_reason: "PagerDuty's own words on every operation in this family: \"This API is in Early Access and may change at any time. Contact your PagerDuty account team to request access.\" This replica has not requested access and cannot — the gate is a conversation with a vendor, not a plan — so PagerDuty's refusal to an unenrolled account IS the true answer. Serving a Contextual Data Platform schema would additionally assert an integration posture (ServiceNow CMDB sync) that this engineering org has never had", mode_reviewed: "2026-09-02", tag: "Enrichment Integrations" }
      - { method: "GET", path: "/enrichment/integrations/servicenow/credentials/{credentials_id}", area: "event-orchestration", tier: 3, status: "deferred", mode: "refuse", mode_reason: "PagerDuty's own words on every operation in this family: \"This API is in Early Access and may change at any time. Contact your PagerDuty account team to request access.\" This replica has not requested access and cannot — the gate is a conversation with a vendor, not a plan — so PagerDuty's refusal to an unenrolled account IS the true answer. Serving a Contextual Data Platform schema would additionally assert an integration posture (ServiceNow CMDB sync) that this engineering org has never had", mode_reviewed: "2026-09-02", tag: "Enrichment Integrations" }
      - { method: "GET", path: "/enrichment/schemas", area: "event-orchestration", tier: 3, status: "deferred", mode: "refuse", mode_reason: "PagerDuty's own words on every operation in this family: \"This API is in Early Access and may change at any time. Contact your PagerDuty account team to request access.\" This replica has not requested access and cannot — the gate is a conversation with a vendor, not a plan — so PagerDuty's refusal to an unenrolled account IS the true answer. Serving a Contextual Data Platform schema would additionally assert an integration posture (ServiceNow CMDB sync) that this engineering org has never had", mode_reviewed: "2026-09-02", tag: "Enrichment Schemas" }
      - { method: "GET", path: "/enrichment/schemas/{schema_id}", area: "event-orchestration", tier: 3, status: "deferred", mode: "refuse", mode_reason: "PagerDuty's own words on every operation in this family: \"This API is in Early Access and may change at any time. Contact your PagerDuty account team to request access.\" This replica has not requested access and cannot — the gate is a conversation with a vendor, not a plan — so PagerDuty's refusal to an unenrolled account IS the true answer. Serving a Contextual Data Platform schema would additionally assert an integration posture (ServiceNow CMDB sync) that this engineering org has never had", mode_reviewed: "2026-09-02", tag: "Enrichment Schemas" }
      - { method: "GET", path: "/enrichment/schemas/{schema_id}/records", area: "event-orchestration", tier: 3, status: "deferred", mode: "refuse", mode_reason: "PagerDuty's own words on every operation in this family: \"This API is in Early Access and may change at any time. Contact your PagerDuty account team to request access.\" This replica has not requested access and cannot — the gate is a conversation with a vendor, not a plan — so PagerDuty's refusal to an unenrolled account IS the true answer. Serving a Contextual Data Platform schema would additionally assert an integration posture (ServiceNow CMDB sync) that this engineering org has never had", mode_reviewed: "2026-09-02", tag: "Enrichment Schemas" }
      - { method: "GET", path: "/escalation_policies", area: "escalation-policies", tier: 1, status: "green", mode: "derive", tag: "Escalation Policies" }
      - { method: "GET", path: "/escalation_policies/{id}", area: "escalation-policies", tier: 1, status: "green", mode: "derive", tag: "Escalation Policies" }
      - { method: "GET", path: "/escalation_policies/{id}/audit/records", area: "escalation-policies", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Escalation Policies" }
      - { method: "GET", path: "/event_orchestrations", area: "event-orchestration", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Event Orchestrations" }
      - { method: "GET", path: "/event_orchestrations/{id}", area: "event-orchestration", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Event Orchestrations" }
      - { method: "GET", path: "/event_orchestrations/{id}/cache_variables", area: "event-orchestration", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Event Orchestrations" }
      - { method: "GET", path: "/event_orchestrations/{id}/cache_variables/{cache_variable_id}", area: "event-orchestration", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Event Orchestrations" }
      - { method: "GET", path: "/event_orchestrations/{id}/cache_variables/{cache_variable_id}/data", area: "event-orchestration", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Event Orchestrations" }
      - { method: "GET", path: "/event_orchestrations/{id}/enablements", area: "event-orchestration", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Event Orchestrations" }
      - { method: "GET", path: "/event_orchestrations/{id}/global", area: "event-orchestration", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Event Orchestrations" }
      - { method: "GET", path: "/event_orchestrations/{id}/integrations", area: "event-orchestration", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Event Orchestrations" }
      - { method: "GET", path: "/event_orchestrations/{id}/integrations/{integration_id}", area: "event-orchestration", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Event Orchestrations" }
      - { method: "GET", path: "/event_orchestrations/{id}/router", area: "event-orchestration", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Event Orchestrations" }
      - { method: "GET", path: "/event_orchestrations/{id}/unrouted", area: "event-orchestration", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Event Orchestrations" }
      - { method: "GET", path: "/event_orchestrations/services/{service_id}", area: "event-orchestration", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Event Orchestrations" }
      - { method: "GET", path: "/event_orchestrations/services/{service_id}/active", area: "event-orchestration", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Event Orchestrations" }
      - { method: "GET", path: "/event_orchestrations/services/{service_id}/cache_variables", area: "event-orchestration", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Event Orchestrations" }
      - { method: "GET", path: "/event_orchestrations/services/{service_id}/cache_variables/{cache_variable_id}", area: "event-orchestration", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Event Orchestrations" }
      - { method: "GET", path: "/event_orchestrations/services/{service_id}/cache_variables/{cache_variable_id}/data", area: "event-orchestration", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Event Orchestrations" }
      - { method: "GET", path: "/extension_schemas", area: "webhooks", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Extension Schemas" }
      - { method: "GET", path: "/extension_schemas/{id}", area: "webhooks", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Extension Schemas" }
      - { method: "GET", path: "/extensions", area: "webhooks", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Extensions" }
      - { method: "GET", path: "/extensions/{id}", area: "webhooks", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Extensions" }
      - { method: "GET", path: "/incident_workflows", area: "automation", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Incident Workflows" }
      - { method: "GET", path: "/incident_workflows/{id}", area: "automation", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Incident Workflows" }
      - { method: "GET", path: "/incident_workflows/actions", area: "automation", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Incident Workflows" }
      - { method: "GET", path: "/incident_workflows/actions/{id}", area: "automation", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Incident Workflows" }
      - { method: "GET", path: "/incident_workflows/triggers", area: "automation", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Incident Workflows" }
      - { method: "GET", path: "/incident_workflows/triggers/{id}", area: "automation", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Incident Workflows" }
      - { method: "GET", path: "/incidents", area: "incidents", tier: 1, status: "green", mode: "derive", tag: "Incidents" }
      - { method: "GET", path: "/incidents/{id}", area: "incidents", tier: 1, status: "green", mode: "derive", tag: "Incidents" }
      - { method: "GET", path: "/incidents/{id}/alerts", area: "incidents", tier: 1, status: "green", mode: "derive", tag: "Incidents" }
      - { method: "GET", path: "/incidents/{id}/alerts/{alert_id}", area: "incidents", tier: 1, status: "green", mode: "derive", tag: "Incidents" }
      - { method: "GET", path: "/incidents/{id}/business_services/impacts", area: "incidents", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Incidents" }
      - { method: "GET", path: "/incidents/{id}/custom_fields/values", area: "incidents", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Incidents" }
      - { method: "GET", path: "/incidents/{id}/log_entries", area: "incidents", tier: 1, status: "deviation", mode: "derive", tag: "Incidents" }
      - { method: "GET", path: "/incidents/{id}/notes", area: "incidents", tier: 1, status: "green", mode: "derive", tag: "Incidents" }
      - { method: "GET", path: "/incidents/{id}/outlier_incident", area: "incidents", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Incidents" }
      - { method: "GET", path: "/incidents/{id}/past_incidents", area: "incidents", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Incidents" }
      - { method: "GET", path: "/incidents/{id}/related_change_events", area: "change-events", tier: 2, status: "green", mode: "derive", mode_reason: "the deploy that landed nearest before the pager went off, on a repo the incident's own service ships from — labelled `most_recent`, which is the ONE of PagerDuty's three correlation reasons this canon can state as a fact. `related_service` would need a service-dependency graph the canon carries no edges for and `intelligent` names a model's output, so neither is emitted rather than being attached to the same row", mode_reviewed: "2026-09-02", tag: "Change Events" }
      - { method: "GET", path: "/incidents/{id}/related_incidents", area: "incidents", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Incidents" }
      - { method: "GET", path: "/incidents/{id}/status_updates/subscribers", area: "incidents", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Incidents" }
      - { method: "GET", path: "/incidents/custom_fields", area: "incident-types", tier: 2, status: "deviation", mode: "derive", mode_reviewed: "2026-09-03", tag: "Incident Custom Fields" }
      - { method: "GET", path: "/incidents/custom_fields/{field_id}", area: "incident-types", tier: 2, status: "deviation", mode: "derive", mode_reviewed: "2026-09-03", tag: "Incident Custom Fields" }
      - { method: "GET", path: "/incidents/custom_fields/{field_id}/field_options", area: "incident-types", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Incident Custom Fields" }
      - { method: "GET", path: "/incidents/types", area: "incident-types", tier: 2, status: "green", mode: "derive", mode_reason: "the ONE incident type PagerDuty ships to every account. Unlike /abilities — where the 2026-09-01 refusal found the document enumerated nothing — this list's contents are stated twice in the pinned document: the 200 on this operation says \"The default incident type will automatically return on this list\", and `IncidentType.parent` says a type with no parent \"is created under top level (`incident_default`)\". So the account has exactly one type until somebody writes another, and writing is out. The two NAMES are PagerDuty's own vocabulary for its own built-in row; the document's EXAMPLE id (P123456) and its 2023 timestamps are NOT copied — the id is minted by the same pdId every other object uses and the timestamps are the org's own creation instant. NOT the documented 402: the captured ability list carries `enable_custom_fields_on_incidents` and `premium_custom_fields`, so refusing would contradict the list published one path over", mode_reviewed: "2026-09-02", tag: "Incident Types" }
      - { method: "GET", path: "/incidents/types/{type_id_or_name}", area: "incident-types", tier: 2, status: "green", mode: "derive", mode_reason: "the ONE incident type PagerDuty ships to every account. Unlike /abilities — where the 2026-09-01 refusal found the document enumerated nothing — this list's contents are stated twice in the pinned document: the 200 on this operation says \"The default incident type will automatically return on this list\", and `IncidentType.parent` says a type with no parent \"is created under top level (`incident_default`)\". So the account has exactly one type until somebody writes another, and writing is out. The two NAMES are PagerDuty's own vocabulary for its own built-in row; the document's EXAMPLE id (P123456) and its 2023 timestamps are NOT copied — the id is minted by the same pdId every other object uses and the timestamps are the org's own creation instant. NOT the documented 402: the captured ability list carries `enable_custom_fields_on_incidents` and `premium_custom_fields`, so refusing would contradict the list published one path over", mode_reviewed: "2026-09-02", tag: "Incident Types" }
      - { method: "GET", path: "/incidents/types/{type_id_or_name}/custom_fields", area: "incident-types", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Incident Types" }
      - { method: "GET", path: "/incidents/types/{type_id_or_name}/custom_fields/{field_id}", area: "incident-types", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Incident Types" }
      - { method: "GET", path: "/incidents/types/{type_id_or_name}/custom_fields/{field_id}/field_options", area: "incident-types", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Incident Types" }
      - { method: "GET", path: "/incidents/types/{type_id_or_name}/custom_fields/{field_id}/field_options/{field_option_id}", area: "incident-types", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Incident Types" }
      - { method: "GET", path: "/ip_allow_lists", area: "licensing", tier: 3, status: "deferred", mode: "refuse", mode_reason: "network-security configuration behind an enrollment gate this replica is not enrolled in: every operation in this family requires the `X-EARLY-ACCESS: ip-allow-lists` header AND an account enrolled in the IP Allow Lists Early Access program, and its own description limits it to \"Account Owners, Global Admins, and Account API Keys\". An allow-list of CIDR ranges is also a claim about network perimeter that a public sandbox has no business simulating", mode_reviewed: "2026-09-02", tag: "IP Allow Lists" }
      - { method: "GET", path: "/ip_allow_lists/{id}", area: "licensing", tier: 3, status: "deferred", mode: "refuse", mode_reason: "network-security configuration behind an enrollment gate this replica is not enrolled in: every operation in this family requires the `X-EARLY-ACCESS: ip-allow-lists` header AND an account enrolled in the IP Allow Lists Early Access program, and its own description limits it to \"Account Owners, Global Admins, and Account API Keys\". An allow-list of CIDR ranges is also a claim about network perimeter that a public sandbox has no business simulating", mode_reviewed: "2026-09-02", tag: "IP Allow Lists" }
      - { method: "GET", path: "/ip_allow_lists/{id}/audit/records", area: "licensing", tier: 3, status: "deferred", mode: "refuse", mode_reason: "network-security configuration behind an enrollment gate this replica is not enrolled in: every operation in this family requires the `X-EARLY-ACCESS: ip-allow-lists` header AND an account enrolled in the IP Allow Lists Early Access program, and its own description limits it to \"Account Owners, Global Admins, and Account API Keys\". An allow-list of CIDR ranges is also a claim about network perimeter that a public sandbox has no business simulating", mode_reviewed: "2026-09-02", tag: "IP Allow Lists" }
      - { method: "GET", path: "/license_allocations", area: "licensing", tier: 3, status: "deferred", mode: "refuse", mode_reason: "account-administration machinery this replica does not model and should not simulate: seat licensing and plan allocation are a BILLING relationship, and this canon models an engineering organization rather than a customer of PagerDuty. There is no canonical row that could answer without inventing a plan for olympus-labs — the exact objection the 2026-09-01 /abilities refusal raised and the capture later answered for THAT row only. PagerDuty's own 4xx is the true answer here, not our coverage 404", mode_reviewed: "2026-09-02", tag: "Licenses" }
      - { method: "GET", path: "/licenses", area: "licensing", tier: 3, status: "deferred", mode: "refuse", mode_reason: "account-administration machinery this replica does not model and should not simulate: seat licensing and plan allocation are a BILLING relationship, and this canon models an engineering organization rather than a customer of PagerDuty. There is no canonical row that could answer without inventing a plan for olympus-labs — the exact objection the 2026-09-01 /abilities refusal raised and the capture later answered for THAT row only. PagerDuty's own 4xx is the true answer here, not our coverage 404", mode_reviewed: "2026-09-02", tag: "Licenses" }
      - { method: "GET", path: "/log_entries", area: "log-entries", tier: 1, status: "deviation", mode: "derive", tag: "Log Entries" }
      - { method: "GET", path: "/log_entries/{id}", area: "log-entries", tier: 1, status: "deviation", mode: "derive", tag: "Log Entries" }
      - { method: "GET", path: "/maintenance_windows", area: "maintenance-windows", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Maintenance Windows" }
      - { method: "GET", path: "/maintenance_windows/{id}", area: "maintenance-windows", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Maintenance Windows" }
      - { method: "GET", path: "/notifications", area: "notifications", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Notifications" }
      - { method: "GET", path: "/oauth_delegations/revocation_requests/status", area: "licensing", tier: 3, status: "deferred", mode: "refuse", mode_reason: "`deprecated: true` upstream (\"deprecated as OAuth token revocation is now synchronous\"), limited by its own description to \"account owners and admins\", AND the document declares NO 200 response for it at all — the responses are 400/401/403/404/429. There is no success shape to conform to, so a 200 of any kind would be a body this replica invented outright", mode_reviewed: "2026-09-02", tag: "OAuth Delegations" }
      - { method: "GET", path: "/oncalls", area: "oncalls", tier: 1, status: "green", mode: "derive", tag: "On-Calls" }
      - { method: "GET", path: "/paused_incident_reports/alerts", area: "analytics", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Paused Incident Reports" }
      - { method: "GET", path: "/paused_incident_reports/counts", area: "analytics", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Paused Incident Reports" }
      - { method: "GET", path: "/priorities", area: "priorities", tier: 1, status: "green", mode: "derive", tag: "Priorities" }
      - { method: "GET", path: "/recommendations/event_orchestrations/rules", area: "recommendations", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Recommendations" }
      - { method: "GET", path: "/rulesets", area: "event-orchestration", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Rulesets" }
      - { method: "GET", path: "/rulesets/{id}", area: "event-orchestration", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Rulesets" }
      - { method: "GET", path: "/rulesets/{id}/rules", area: "event-orchestration", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Rulesets" }
      - { method: "GET", path: "/rulesets/{id}/rules/{rule_id}", area: "event-orchestration", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Rulesets" }
      - { method: "GET", path: "/schedules", area: "schedules", tier: 1, status: "green", mode: "derive", tag: "Schedules" }
      - { method: "GET", path: "/schedules/{id}", area: "schedules", tier: 1, status: "green", mode: "derive", tag: "Schedules" }
      - { method: "GET", path: "/schedules/{id}/audit/records", area: "schedules", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Schedules" }
      - { method: "GET", path: "/schedules/{id}/overrides", area: "schedules", tier: 1, status: "green", mode: "derive", mode_reason: "hello-13's ScheduleOverride canon: two people covered somebody else's shift, and `replaces` names the person the rotation formula produces across the window so an override can never disagree with the schedule it overrides", mode_reviewed: "2026-09-02", tag: "Schedules" }
      - { method: "GET", path: "/schedules/{id}/users", area: "schedules", tier: 1, status: "green", mode: "derive", tag: "Schedules" }
      - { method: "GET", path: "/service_dependencies/business_services/{id}", area: "business-services", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Service Dependencies" }
      - { method: "GET", path: "/service_dependencies/technical_services/{id}", area: "business-services", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Service Dependencies" }
      - { method: "GET", path: "/services", area: "services", tier: 1, status: "green", mode: "derive", tag: "Services" }
      - { method: "GET", path: "/services/{id}", area: "services", tier: 1, status: "green", mode: "derive", tag: "Services" }
      - { method: "GET", path: "/services/{id}/audit/records", area: "services", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Services" }
      - { method: "GET", path: "/services/{id}/change_events", area: "change-events", tier: 2, status: "green", mode: "derive", mode_reason: "canon's `Deployment` rows in PagerDuty's own vocabulary — its `related_change_events` operation defines a change event as \"service changes such as deploys, build completion, and configuration changes\", which is the entity the git canon already records: a real commit, to a real environment, by a real person. `custom_details.commit` is the SAME sha every git host serves for that deploy, so a responder can follow one change across providers (invariant #5). `integration`, `routing_key`, `source`, `links` and `images` are omitted because this universe has no inbound integration — the reason the renderer already omits `Service.integrations`. `change_events` is one of the 53 names in the captured /abilities response, so the surface and the ability list agree", mode_reviewed: "2026-09-02", tag: "Change Events" }
      - { method: "GET", path: "/services/{id}/custom_fields/values", area: "services", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Services" }
      - { method: "GET", path: "/services/{id}/enablements", area: "services", tier: 1, status: "green", mode: "derive", mode_reason: "the document supports exactly one feature here (`aiops`) and says an unentitled account gets a warning alongside the data. NO AIOps name appears in the 53-name captured /abilities response this replica serves, so `enabled: true` would contradict the list published one path over (invariant #5) — the entitlement is READ from our own ability list rather than chosen. The document leaves `enabled` unstated for the unentitled case and `false` is the only reading consistent with \"not entitled to use\"; the ambiguity is recorded in DECISIONS 2026-09-02 [pagerduty/enablements]. `updated_at` is omitted because nobody has ever changed a setting nobody can change", mode_reviewed: "2026-09-02", tag: "Services" }
      - { method: "GET", path: "/services/{id}/integrations/{integration_id}", area: "services", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Services" }
      - { method: "GET", path: "/services/{id}/rules", area: "services", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Services" }
      - { method: "GET", path: "/services/{id}/rules/{rule_id}", area: "services", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Services" }
      - { method: "GET", path: "/services/custom_fields", area: "services", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Service Custom Fields" }
      - { method: "GET", path: "/services/custom_fields/{field_id}", area: "services", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Service Custom Fields" }
      - { method: "GET", path: "/services/custom_fields/{field_id}/field_options", area: "services", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Service Custom Fields" }
      - { method: "GET", path: "/services/custom_fields/{field_id}/field_options/{field_option_id}", area: "services", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Service Custom Fields" }
      - { method: "GET", path: "/session_configurations", area: "licensing", tier: 3, status: "deferred", mode: "refuse", mode_reason: "account session-security policy (absolute and idle session TTLs), which is administration rather than engineering data — and the document states PagerDuty's own answer for an account that has not configured one: \"If no configurations exist, a 404 Not Found error will be returned. A Session Configuration needs to be created before it can be retrieved.\" Creating one is a write, so the 404 IS this account's true answer rather than a coverage gap", mode_reviewed: "2026-09-02", tag: "Session Configurations" }
      - { method: "GET", path: "/sre_agent/memories", area: "recommendations", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "SRE Agent" }
      - { method: "GET", path: "/standards", area: "standards", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Standards" }
      - { method: "GET", path: "/standards/scores/{resource_type}", area: "standards", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Standards" }
      - { method: "GET", path: "/standards/scores/{resource_type}/{id}", area: "standards", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Standards" }
      - { method: "GET", path: "/status_dashboards", area: "status-dashboards", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Status Dashboards" }
      - { method: "GET", path: "/status_dashboards/{id}", area: "status-dashboards", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Status Dashboards" }
      - { method: "GET", path: "/status_dashboards/{id}/service_impacts", area: "status-dashboards", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Status Dashboards" }
      - { method: "GET", path: "/status_dashboards/url_slugs/{url_slug}", area: "status-dashboards", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Status Dashboards" }
      - { method: "GET", path: "/status_dashboards/url_slugs/{url_slug}/service_impacts", area: "status-dashboards", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Status Dashboards" }
      - { method: "GET", path: "/status_pages", area: "status-pages", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Status Pages" }
      - { method: "GET", path: "/status_pages/{id}/impacts", area: "status-pages", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Status Pages" }
      - { method: "GET", path: "/status_pages/{id}/impacts/{impact_id}", area: "status-pages", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Status Pages" }
      - { method: "GET", path: "/status_pages/{id}/posts", area: "status-pages", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Status Pages" }
      - { method: "GET", path: "/status_pages/{id}/posts/{post_id}", area: "status-pages", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Status Pages" }
      - { method: "GET", path: "/status_pages/{id}/posts/{post_id}/post_updates", area: "status-pages", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Status Pages" }
      - { method: "GET", path: "/status_pages/{id}/posts/{post_id}/post_updates/{post_update_id}", area: "status-pages", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Status Pages" }
      - { method: "GET", path: "/status_pages/{id}/posts/{post_id}/postmortem", area: "status-pages", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Status Pages" }
      - { method: "GET", path: "/status_pages/{id}/services", area: "status-pages", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Status Pages" }
      - { method: "GET", path: "/status_pages/{id}/services/{service_id}", area: "status-pages", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Status Pages" }
      - { method: "GET", path: "/status_pages/{id}/severities", area: "status-pages", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Status Pages" }
      - { method: "GET", path: "/status_pages/{id}/severities/{severity_id}", area: "status-pages", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Status Pages" }
      - { method: "GET", path: "/status_pages/{id}/statuses", area: "status-pages", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Status Pages" }
      - { method: "GET", path: "/status_pages/{id}/statuses/{status_id}", area: "status-pages", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Status Pages" }
      - { method: "GET", path: "/status_pages/{id}/subscriptions", area: "status-pages", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Status Pages" }
      - { method: "GET", path: "/status_pages/{id}/subscriptions/{subscription_id}", area: "status-pages", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Status Pages" }
      - { method: "GET", path: "/tags", area: "tags", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Tags" }
      - { method: "GET", path: "/tags/{id}", area: "tags", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Tags" }
      - { method: "GET", path: "/tags/{id}/{entity_type}", area: "tags", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Tags" }
      - { method: "GET", path: "/teams", area: "teams", tier: 1, status: "green", mode: "derive", tag: "Teams" }
      - { method: "GET", path: "/teams/{id}", area: "teams", tier: 1, status: "green", mode: "derive", tag: "Teams" }
      - { method: "GET", path: "/teams/{id}/audit/records", area: "teams", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Teams" }
      - { method: "GET", path: "/teams/{id}/members", area: "teams", tier: 1, status: "green", mode: "derive", tag: "Teams" }
      - { method: "GET", path: "/teams/{id}/notification_subscriptions", area: "teams", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Teams" }
      - { method: "GET", path: "/templates", area: "addons", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Templates" }
      - { method: "GET", path: "/templates/{id}", area: "addons", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Templates" }
      - { method: "GET", path: "/templates/fields", area: "addons", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Templates" }
      - { method: "GET", path: "/users", area: "users", tier: 1, status: "green", mode: "derive", tag: "Users" }
      - { method: "GET", path: "/users/{id}", area: "users", tier: 1, status: "green", mode: "derive", tag: "Users" }
      - { method: "GET", path: "/users/{id}/audit/records", area: "users", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Users" }
      - { method: "GET", path: "/users/{id}/contact_methods", area: "users", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Users" }
      - { method: "GET", path: "/users/{id}/contact_methods/{contact_method_id}", area: "users", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Users" }
      - { method: "GET", path: "/users/{id}/license", area: "users", tier: 1, status: "planned", mode: "refuse", mode_reason: "account-administration machinery this replica does not model and should not simulate: seat licensing and plan allocation are a BILLING relationship, and this canon models an engineering organization rather than a customer of PagerDuty. There is no canonical row that could answer without inventing a plan for olympus-labs — the exact objection the 2026-09-01 /abilities refusal raised and the capture later answered for THAT row only. PagerDuty's own 4xx is the true answer here, not our coverage 404", mode_reviewed: "2026-09-02", tag: "Users" }
      - { method: "GET", path: "/users/{id}/notification_rules", area: "users", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Users" }
      - { method: "GET", path: "/users/{id}/notification_rules/{notification_rule_id}", area: "users", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Users" }
      - { method: "GET", path: "/users/{id}/notification_subscriptions", area: "users", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Users" }
      - { method: "GET", path: "/users/{id}/oauth_delegations", area: "users", tier: 1, status: "planned", mode: "refuse", mode_reason: "live authentication machinery, not engineering-org data: an inventory of the OAuth tokens and browser sessions currently issued against the account is a security surface whose truthful content changes by the minute and whose simulated content would be a set of credentials that authenticate nothing. The canon records no session and no token, and a replica that invented one would be publishing credential-shaped strings", mode_reviewed: "2026-09-02", tag: "Users" }
      - { method: "GET", path: "/users/{id}/oauth_delegations/{delegation_id}", area: "users", tier: 1, status: "planned", mode: "refuse", mode_reason: "live authentication machinery, not engineering-org data: an inventory of the OAuth tokens and browser sessions currently issued against the account is a security surface whose truthful content changes by the minute and whose simulated content would be a set of credentials that authenticate nothing. The canon records no session and no token, and a replica that invented one would be publishing credential-shaped strings", mode_reviewed: "2026-09-02", tag: "Users" }
      - { method: "GET", path: "/users/{id}/oncall_handoff_notification_rules", area: "users", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Users" }
      - { method: "GET", path: "/users/{id}/oncall_handoff_notification_rules/{oncall_handoff_notification_rule_id}", area: "users", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Users" }
      - { method: "GET", path: "/users/{id}/sessions", area: "users", tier: 1, status: "planned", mode: "refuse", mode_reason: "live authentication machinery, not engineering-org data: an inventory of the OAuth tokens and browser sessions currently issued against the account is a security surface whose truthful content changes by the minute and whose simulated content would be a set of credentials that authenticate nothing. The canon records no session and no token, and a replica that invented one would be publishing credential-shaped strings. This operation is ALSO `deprecated: true` upstream with a documented replacement (the List OAuth Delegations endpoint) — a retirement candidate recorded in the review doc, deliberately NOT armed in the gateway registry here because PagerDuty has published no removal date", mode_reviewed: "2026-09-02", tag: "Users" }
      - { method: "GET", path: "/users/{id}/sessions/{type}/{session_id}", area: "users", tier: 1, status: "planned", mode: "refuse", mode_reason: "live authentication machinery, not engineering-org data: an inventory of the OAuth tokens and browser sessions currently issued against the account is a security surface whose truthful content changes by the minute and whose simulated content would be a set of credentials that authenticate nothing. The canon records no session and no token, and a replica that invented one would be publishing credential-shaped strings. This operation is ALSO `deprecated: true` upstream with a documented replacement (the List OAuth Delegations endpoint) — a retirement candidate recorded in the review doc, deliberately NOT armed in the gateway registry here because PagerDuty has published no removal date", mode_reviewed: "2026-09-02", tag: "Users" }
      - { method: "GET", path: "/users/{id}/status_update_notification_rules", area: "users", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Users" }
      - { method: "GET", path: "/users/{id}/status_update_notification_rules/{status_update_notification_rule_id}", area: "users", tier: 1, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Users" }
      - { method: "GET", path: "/users/me", area: "users", tier: 1, status: "green", mode: "derive", tag: "Users" }
      - { method: "GET", path: "/v3/schedules", area: "schedules", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Schedules_v3" }
      - { method: "GET", path: "/v3/schedules/{id}", area: "schedules", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Schedules_v3" }
      - { method: "GET", path: "/v3/schedules/{id}/audit/records", area: "schedules", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Schedules_v3" }
      - { method: "GET", path: "/v3/schedules/{id}/custom_shifts", area: "schedules", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Schedules_v3" }
      - { method: "GET", path: "/v3/schedules/{id}/custom_shifts/{custom_shift_id}", area: "schedules", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Schedules_v3" }
      - { method: "GET", path: "/v3/schedules/{id}/overrides", area: "schedules", tier: 2, status: "green", mode: "derive", mode_reason: "the v3 rendering of the same two ScheduleOverride rows as OverrideShift; rotation_id and custom_shift_id are omitted rather than invented, this canon has neither entity", mode_reviewed: "2026-09-02", tag: "Schedules_v3" }
      - { method: "GET", path: "/v3/schedules/{id}/overrides/{override_id}", area: "schedules", tier: 2, status: "green", mode: "derive", mode_reason: "one override by id, byte-identical to the row the v3 list served; an id this rotation never issued is a 404", mode_reviewed: "2026-09-02", tag: "Schedules_v3" }
      - { method: "GET", path: "/v3/schedules/{id}/rotations", area: "schedules", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Schedules_v3" }
      - { method: "GET", path: "/v3/schedules/{id}/rotations/{rotation_id}", area: "schedules", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Schedules_v3" }
      - { method: "GET", path: "/v3/schedules/{id}/rotations/{rotation_id}/events", area: "schedules", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Schedules_v3" }
      - { method: "GET", path: "/v3/schedules/{id}/rotations/{rotation_id}/events/{event_id}", area: "schedules", tier: 2, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Schedules_v3" }
      - { method: "GET", path: "/vendors", area: "vendors", tier: 2, status: "green", mode: "derive", mode_reason: "hello-13's `features.vendorCatalog`: twelve FICTIONAL integration partners, structure in canon's VENDOR_CATALOG, names and directory copy in themes/greek/vendors.ts, baked into the artifact's `vendor` table at compile. This REPLACES the 2026-09-02-morning `empty` ruling, which was itself a knowing deviation — the founder's afternoon ruling took the third option over both serving nothing and printing real companies' names. A pre-catalogue artifact (both frozen g7 pins) still answers 200 + the empty envelope, deliberately, not a generation gap", mode_reviewed: "2026-09-02", tag: "Vendors" }
      - { method: "GET", path: "/vendors/{id}", area: "vendors", tier: 2, status: "green", mode: "derive", mode_reason: "one partner by id, byte-identical to the row the catalogue list served; an id this catalogue never issued is the document's own 404. The `{\"vendor\": [<Vendor>]}` ARRAY envelope is the pinned document's, not ours — the only single-object GET in it wearing a collection envelope, and no 200 on this provider has ever been captured to contradict it (coverage/provider-pins.yaml capture-pending)", mode_reviewed: "2026-09-02", tag: "Vendors" }
      - { method: "GET", path: "/webhook_subscriptions", area: "webhooks", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Webhooks" }
      - { method: "GET", path: "/webhook_subscriptions/{id}", area: "webhooks", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Webhooks" }
      - { method: "GET", path: "/webhook_subscriptions/oauth_clients", area: "webhooks", tier: 3, status: "deferred", mode: "refuse", mode_reason: "live authentication machinery, not engineering-org data: an inventory of the OAuth tokens and browser sessions currently issued against the account is a security surface whose truthful content changes by the minute and whose simulated content would be a set of credentials that authenticate nothing. The canon records no session and no token, and a replica that invented one would be publishing credential-shaped strings", mode_reviewed: "2026-09-02", tag: "Webhooks" }
      - { method: "GET", path: "/webhook_subscriptions/oauth_clients/{id}", area: "webhooks", tier: 3, status: "deferred", mode: "refuse", mode_reason: "live authentication machinery, not engineering-org data: an inventory of the OAuth tokens and browser sessions currently issued against the account is a security surface whose truthful content changes by the minute and whose simulated content would be a set of credentials that authenticate nothing. The canon records no session and no token, and a replica that invented one would be publishing credential-shaped strings", mode_reviewed: "2026-09-02", tag: "Webhooks" }
      - { method: "GET", path: "/workflows/integrations", area: "automation", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Workflow Integrations" }
      - { method: "GET", path: "/workflows/integrations/{id}", area: "automation", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Workflow Integrations" }
      - { method: "GET", path: "/workflows/integrations/{integration_id}/connections", area: "automation", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Workflow Integrations" }
      - { method: "GET", path: "/workflows/integrations/{integration_id}/connections/{id}", area: "automation", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Workflow Integrations" }
      - { method: "GET", path: "/workflows/integrations/connections", area: "automation", tier: 3, status: "green", mode: "derive", mode_reviewed: "2026-09-03", tag: "Workflow Integrations" }
    graphql: [] # no GraphQL API exists for this provider (REST-only)
  salesforce:
    rest:
      - { method: "GET", path: "/services/data", area: "versions", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED, and served VERBATIM from a captured response (packages/conformance/specs/salesforce/captures/versions.json, sha-pinned in coverage/provider-pins.yaml under salesforce.captures-file) — the pagerduty /abilities precedent. This is the ONLY Salesforce response anybody can observe without an org: every path under /services/data/v{version}/ answers 401 to an anonymous caller because auth runs before routing. Thirty-seven entries, v31.0 to v67.0, including the one label upstream spells with U+2019 rather than an apostrophe; salesforce/versions.test.ts binds the renderer's constant to the capture and to its sha so a well-meaning ASCII cleanup cannot turn the capture into a construction", mode_reviewed: "2026-09-04", tag: "Versions" }
      - { method: "GET", path: "/services/data/{version}", area: "resources", tier: 1, status: "planned", mode: "derive", mode_reason: "NOT canon-blocked, and the distinction is the point of classifying it separately: the resource map is a list of the resources THIS replica routes, so it is buildable the day somebody writes it rather than the day a pin rides the CRM canon. It is unserved for one reason only — no capture reaches it (401 before routing, recorded under salesforce.capture-pending) and the hand-authored document therefore declares no shape for it, so serving one would mean publishing a body nobody has seen", mode_reviewed: "2026-09-04", tag: "Resources" }
      - { method: "GET", path: "/services/data/{version}/actions", area: "actions", tier: 3, status: "deferred", mode: "generate", mode_reason: "the invocable-action catalogue reflects an org's automation, which the CRM canon does not model yet and no capture reaches", mode_reviewed: "2026-09-04", tag: "Actions" }
      - { method: "GET", path: "/services/data/{version}/actions/custom", area: "actions", tier: 3, status: "green", mode: "empty", mode_reason: "olympus-labs' Salesforce org defines no custom invocable action - canon models no Flow, no Apex class and no automation on the CRM side, and this replica accepts no writes; Salesforce's own answer for an org with none is an empty actions collection at 200. RULED by the founder 2026-09-12 (round 19), coverage wave W5", mode_reviewed: "2026-09-12", tag: "Actions" }
      - { method: "GET", path: "/services/data/{version}/actions/standard", area: "actions", tier: 3, status: "deferred", mode: "generate", mode_reason: "the invocable-action catalogue reflects an org's automation, which the CRM canon does not model yet and no capture reaches", mode_reviewed: "2026-09-04", tag: "Actions" }
      - { method: "GET", path: "/services/data/{version}/analytics/dashboards", area: "analytics-reports", tier: 3, status: "deferred", mode: "generate", mode_reason: "the Reports and Dashboards API is a separate product surface over the same records: it needs the CRM canon first, and then report definitions the canon does not model", mode_reviewed: "2026-09-04", tag: "Analytics Reports" }
      - { method: "GET", path: "/services/data/{version}/analytics/dashboards/{dashboardId}", area: "analytics-reports", tier: 3, status: "deferred", mode: "generate", mode_reason: "the Reports and Dashboards API is a separate product surface over the same records: it needs the CRM canon first, and then report definitions the canon does not model", mode_reviewed: "2026-09-04", tag: "Analytics Reports" }
      - { method: "GET", path: "/services/data/{version}/analytics/reports", area: "analytics-reports", tier: 3, status: "deferred", mode: "generate", mode_reason: "the Reports and Dashboards API is a separate product surface over the same records: it needs the CRM canon first, and then report definitions the canon does not model", mode_reviewed: "2026-09-04", tag: "Analytics Reports" }
      - { method: "GET", path: "/services/data/{version}/analytics/reports/{reportId}", area: "analytics-reports", tier: 3, status: "deferred", mode: "generate", mode_reason: "the Reports and Dashboards API is a separate product surface over the same records: it needs the CRM canon first, and then report definitions the canon does not model", mode_reviewed: "2026-09-04", tag: "Analytics Reports" }
      - { method: "GET", path: "/services/data/{version}/analytics/reports/{reportId}/describe", area: "analytics-reports", tier: 3, status: "deferred", mode: "generate", mode_reason: "the Reports and Dashboards API is a separate product surface over the same records: it needs the CRM canon first, and then report definitions the canon does not model", mode_reviewed: "2026-09-04", tag: "Analytics Reports" }
      - { method: "GET", path: "/services/data/{version}/analytics/reports/{reportId}/instances", area: "analytics-reports", tier: 3, status: "deferred", mode: "generate", mode_reason: "the Reports and Dashboards API is a separate product surface over the same records: it needs the CRM canon first, and then report definitions the canon does not model", mode_reviewed: "2026-09-04", tag: "Analytics Reports" }
      - { method: "GET", path: "/services/data/{version}/appMenu/{appMenuType}", area: "ui-metadata", tier: 3, status: "deferred", mode: "generate", mode_reason: "tabs, theme, recently-viewed and the app menu are per-org and per-USER state; nothing in this universe carries a Salesforce user's recent-item list yet", mode_reviewed: "2026-09-04", tag: "User Interface" }
      - { method: "GET", path: "/services/data/{version}/composite/sobjects/{sObject}", area: "composite", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED (wave W5). The reason this row carried until 2026-09-12 — `composite batches the operations above; it can be no more real than they are` — was true and is now an argument FOR serving it: the operation it batches IS served, so the batch is exactly as real as the retrieve. It reads up to 800 records of one type by Id, every one of them a record the by-id projection already produces, and conformance asserts the batch equals the one-by-one reads element for element. An Id that names nothing is a `null` IN POSITION, which is Salesforce's own answer and the reason the response is positional: dropping a miss would shift every record after it onto the wrong id. `fields` is required on the GET form, the 800-record limit is enforced rather than quietly honoured, and both refusals carry the operation's own `INVALID_INPUT`", mode_reviewed: "2026-09-12", tag: "Composite" }
      - { method: "GET", path: "/services/data/{version}/jobs/ingest", area: "bulk", tier: 3, status: "deferred", mode: "generate", mode_reason: "Bulk 2.0 job state is a record of asynchronous work; a read-only universe has no jobs until the canon generates a history of them", mode_reviewed: "2026-09-04", tag: "Bulk" }
      - { method: "GET", path: "/services/data/{version}/jobs/ingest/{jobId}", area: "bulk", tier: 3, status: "deferred", mode: "generate", mode_reason: "Bulk 2.0 job state is a record of asynchronous work; a read-only universe has no jobs until the canon generates a history of them", mode_reviewed: "2026-09-04", tag: "Bulk" }
      - { method: "GET", path: "/services/data/{version}/jobs/query", area: "bulk", tier: 3, status: "deferred", mode: "generate", mode_reason: "Bulk 2.0 job state is a record of asynchronous work; a read-only universe has no jobs until the canon generates a history of them", mode_reviewed: "2026-09-04", tag: "Bulk" }
      - { method: "GET", path: "/services/data/{version}/jobs/query/{jobId}", area: "bulk", tier: 3, status: "deferred", mode: "generate", mode_reason: "Bulk 2.0 job state is a record of asynchronous work; a read-only universe has no jobs until the canon generates a history of them", mode_reviewed: "2026-09-04", tag: "Bulk" }
      - { method: "GET", path: "/services/data/{version}/jobs/query/{jobId}/results", area: "bulk", tier: 3, status: "deferred", mode: "generate", mode_reason: "Bulk 2.0 job state is a record of asynchronous work; a read-only universe has no jobs until the canon generates a history of them", mode_reviewed: "2026-09-04", tag: "Bulk" }
      - { method: "GET", path: "/services/data/{version}/limits", area: "limits", tier: 2, status: "deferred", mode: "generate", mode_reason: "an org's limits and per-sObject record counts are facts about THIS simulated org, not about Salesforce. Serving numbers before the CRM canon exists would mean inventing them", mode_reviewed: "2026-09-04", tag: "Limits" }
      - { method: "GET", path: "/services/data/{version}/limits/recordCount", area: "limits", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED (wave W5). The blocker this row named — `serving numbers before the CRM canon exists would mean inventing them` — was cleared by hello-14, which ships the CRM canon and rides every artifact from `sf-v67-g9` forward. recordCount is `{sObjects: [{count, name}]}` over exactly the four objects this host describes, every count is a row count in the artifact, and conformance asserts each against a `SELECT COUNT()` on the same object so the two surfaces cannot disagree. `/limits` ITSELF STAYS UNSERVED and that is the honest half of this row: an org's API request allowances, storage figures and license counts are facts this universe does not carry, and recordCount is the one part of that resource that is nothing but a count of rows already served. An object this replica does not serve earns the coverage refusal rather than a silent omission — a missing row would report nothing for an object that has plenty", mode_reviewed: "2026-09-12", tag: "Limits" }
      - { method: "GET", path: "/services/data/{version}/parameterizedSearch", area: "sosl-search", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED (wave W5), by the SAME bounded SOSL engine `/search` runs — one grammar, two spellings, so `what does the word acme match` has exactly one answer on this host. Both blockers this row named are cleared: the CRM canon landed with hello-14 and the query grammar with the SOQL parser on 2026-09-04, and what was left was renderer work of exactly the kind soql.ts already did. `q` goes through the same term parser that reads the inside of a `FIND {}` clause; `sobject`, `fields`, `in` and `overallLimit` are covered; and an unrecognized parameter is refused BY NAME rather than ignored, because `spellCorrection`, `highlight`, `netId` and the per-object `where` family each NARROW or ANNOTATE a result and honouring the request minus one returns a wider answer than the caller asked for", mode_reviewed: "2026-09-12", tag: "Search" }
      - { method: "GET", path: "/services/data/{version}/process/approvals", area: "process", tier: 3, status: "green", mode: "empty", mode_reason: "olympus-labs' Salesforce org defines no approval process - canon models no approval automation on the CRM side (the one approval_rule row is a code-review rule over repo-01) and this replica accepts no writes; Salesforce's own answer for an org with none is an empty approvals collection at 200. RULED by the founder 2026-09-12 (round 19), coverage wave W5. The collection is a MAP keyed by sObject name rather than an array, which is Salesforce's own shape, so the empty one is {}", mode_reviewed: "2026-09-12", tag: "Process" }
      - { method: "GET", path: "/services/data/{version}/process/rules", area: "process", tier: 3, status: "green", mode: "empty", mode_reason: "olympus-labs' Salesforce org defines no workflow rule - canon models no CRM automation and this replica accepts no writes; Salesforce's own answer for an org with none is {\"rules\": []} at 200. RULED by the founder 2026-09-12 (round 19), coverage wave W5", mode_reviewed: "2026-09-12", tag: "Process" }
      - { method: "GET", path: "/services/data/{version}/process/rules/{sObject}", area: "process", tier: 3, status: "green", mode: "empty", mode_reason: "olympus-labs' Salesforce org defines no workflow rule - canon models no CRM automation and this replica accepts no writes; Salesforce's own answer for an org with none is {\"rules\": []} at 200. RULED by the founder 2026-09-12 (round 19), coverage wave W5. Asserted on all four served objects, because `no workflow rule anywhere` is a claim about every one of them; an object this replica does not serve still earns the coverage 404, so the ruling never answers a typo confidently", mode_reviewed: "2026-09-12", tag: "Process" }
      - { method: "GET", path: "/services/data/{version}/query", area: "soql-query", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED. Both blockers named on this row are cleared: hello-14 supplies the records, and the serving wave supplied the BOUNDED SOQL PARSER — SELECT (incl. COUNT()), FROM over the four serve-plan objects, WHERE with AND/OR/NOT/parens/IN/LIKE, ORDER BY with NULLS placement, LIMIT and OFFSET. Every construct outside that subset is refused BY NAME with a 400 and the query coverage headers, never approximated and never silently dropped — a WHERE clause the parser did not understand and skipped would return more rows than the caller asked for and look exactly like a correct answer, which the caller cannot detect. Relative date literals resolve against the artifact ANCHOR, not the wall clock, so a pinned snapshot answers the same query forever. renderer-jira's bounded JQL is the precedent, including its two-tier error: a coverage refusal carries the pointer, a caller's syntax error does not", mode_reviewed: "2026-09-04", tag: "Query" }
      - { method: "GET", path: "/services/data/{version}/query/{queryLocator}", area: "soql-query", tier: 1, status: "planned", mode: "refuse", mode_reason: "this host never issues a query locator - one is minted only when a result exceeds QUERY_BATCH_SIZE (2000, renderer-salesforce/src/soql.ts) and the largest served object has 120 records - so the route can only be reached with a locator it did not issue, and Salesforce's own INVALID_QUERY_LOCATOR is the whole answer (the proposal already stands in coverage/reviews/2026-09-08-modes-generation-claims.md). RULED by the founder 2026-09-12 (round 19), coverage wave W5. 400, because this is a malformed continuation rather than a missing resource: the route exists and was reached, and it was the ARGUMENT that could not be honoured", mode_reviewed: "2026-09-12", tag: "Query" }
      - { method: "GET", path: "/services/data/{version}/queryAll", area: "soql-query", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED (wave W5), and this row OVERTURNS ITS OWN EARLIER REASON — flagged as a founder call in the wave's PR. The 2026-09-08 reading was that queryAll returning exactly what query returns is `a fact about THIS universe, not about the operation`. The correction is that queryAll is SPECIFIED as `query, plus the deleted and archived rows`, and running that specification against an organization that has deleted and archived nothing produces query's output by the operation's own definition — the same way `WHERE IsDeleted = true` correctly returns nothing here. Refusing it was refusing to compute a specified answer because the answer looked too easy. The client-reliance worry is answered rather than dismissed: nothing on the wire tells a caller the two are identical, and the conformance entry asserts IsDeleted is false on every record BEFORE it compares the two, so the day canon deletes something the row goes red rather than going on serving a claim that has quietly become false. If the earlier reading is preferred the route comes out and this row returns to `generate` `record deletion and archival history`, with nothing else in the wave touched", mode_reviewed: "2026-09-12", tag: "Query" }
      - { method: "GET", path: "/services/data/{version}/queryAll/{queryLocator}", area: "soql-query", tier: 1, status: "planned", mode: "refuse", mode_reason: "this host never issues a query locator - one is minted only when a result exceeds QUERY_BATCH_SIZE (2000, renderer-salesforce/src/soql.ts) and the largest served object has 120 records - so the route can only be reached with a locator it did not issue, and Salesforce's own INVALID_QUERY_LOCATOR is the whole answer (the proposal already stands in coverage/reviews/2026-09-08-modes-generation-claims.md). RULED by the founder 2026-09-12 (round 19), coverage wave W5. The other blocker this row used to name is gone rather than waived: /queryAll is served now, so the only thing standing here is the locator", mode_reviewed: "2026-09-12", tag: "Query" }
      - { method: "GET", path: "/services/data/{version}/recent", area: "ui-metadata", tier: 3, status: "green", mode: "empty", mode_reason: "no user has viewed a record in this replica - the recently-viewed list is per-user UI state written by the Salesforce web app, this universe carries no Salesforce session, and the served describe reports mruEnabled false for exactly that reason; Salesforce's own answer for a user who has viewed nothing is [] at 200. RULED by the founder 2026-09-12 (round 19), coverage wave W5. This is the row that gives `mruEnabled: false` a resource behind it: the conformance entry asserts both halves, so the flag and the list cannot come to say different things", mode_reviewed: "2026-09-12", tag: "User Interface" }
      - { method: "GET", path: "/services/data/{version}/search", area: "sosl-search", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED (wave W5) by a BOUNDED SOSL parser — the soql.ts pattern applied a second time, with the same contract: every construct outside the subset is refused BY NAME with a 400 and the query coverage headers, never approximated and never silently dropped. Both blockers this row named are cleared: the CRM canon landed with hello-14 and the query grammar with the SOQL parser on 2026-09-04. COVERED: `FIND {term}`/`FIND 'term'` over one word (optionally ending in `*`) or one quoted phrase, `IN ALL|NAME|EMAIL|PHONE FIELDS`, `RETURNING Object(fields)` and `LIMIT`. REFUSED BY NAME: a multi-word term — because Salesforce's default operator between bare terms is not something this repository can check (developer.salesforce.com answers 403 to every machine fetch) and the two candidate readings return DIFFERENT result sets — plus AND/OR/NOT, interior wildcards, `IN SIDEBAR FIELDS` (org UI configuration canon does not model) and every sub-clause of a RETURNING. One narrowing is stated rather than hidden: this replica matches record TEXT only, where Salesforce also matches adjacent objects at a lower priority, which makes the result set narrower than the real API's and never wider", mode_reviewed: "2026-09-12", tag: "Search" }
      - { method: "GET", path: "/services/data/{version}/search/layout", area: "sosl-search", tier: 2, status: "deferred", mode: "generate", mode_reason: "SOSL searches across objects, so it needs the CRM canon AND the query grammar SOQL needs; it follows /query rather than leading it", mode_reviewed: "2026-09-04", tag: "Search" }
      - { method: "GET", path: "/services/data/{version}/search/scopeOrder", area: "sosl-search", tier: 2, status: "deferred", mode: "generate", mode_reason: "SOSL searches across objects, so it needs the CRM canon AND the query grammar SOQL needs; it follows /query rather than leading it", mode_reviewed: "2026-09-04", tag: "Search" }
      - { method: "GET", path: "/services/data/{version}/sobjects", area: "sobject-describe", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED (wave W5). describeGlobal's `sobjects` array is the SUMMARY half of the describe this host already serves, and the wave made that literally true rather than nearly true: `objectDescribe()` in packages/renderer-salesforce/src/describe.ts is the full describe MINUS `fields` and `childRelationships`, computed by deleting those two keys rather than by writing a second literal, which is Salesforce's own relationship between its two describe types. So this host cannot report `queryable: true` on one surface and `queryable: false` on the other for the same object, and conformance asserts the global summary against the describe ROUTE as well as against the renderer. `encoding` and `maxBatchSize` are facts about the API rather than about the org. The operation's evidence was `path-only`, so this wave declared its shape under the `hand-authored` class the describe row established. Listing exactly the four served objects is a true statement about THIS replica — the same statement the describe's coverage 404 makes about a fifth", mode_reviewed: "2026-09-12", tag: "sObject Describe" }
      - { method: "GET", path: "/services/data/{version}/sobjects/{sObject}", area: "sobject-describe", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED (wave W5): `{objectDescribe, recentItems}`, where `objectDescribe` is the same summary describeGlobal lists. The one shape ruling this row owed is made and is not a stub — `recentItems` is EMPTY, because a most-recently-used list is per-USER interface state written by the Salesforce web app and this universe carries no Salesforce session, which is the same fact the describe beside it publishes as `mruEnabled: false`. Conformance asserts BOTH halves on one response, so the flag and the list cannot come to say different things. The row stays `derive` rather than `empty`: `objectDescribe` carries real content, and `empty` names a row whose WHOLE answer is nothing — that row is `/recent`, ruled on this same fact", mode_reviewed: "2026-09-12", tag: "sObject Describe" }
      - { method: "GET", path: "/services/data/{version}/sobjects/{sObject}/{fieldName}/{fieldValue}", area: "sobject-rows", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED (wave W5): retrieve by EXTERNAL ID over the `idLookup` fields the describe already advertises — every Id, plus Contact.Email and Case.CaseNumber. Conformance asserts the record it answers is BYTE-IDENTICAL to the one the by-id retrieve answers, and walks every field the describe marks idLookup so a flag this host publishes cannot advertise a lookup that does not work. The ruling this row owed is made: a lookup on a field whose `idLookup` is FALSE is refused BY NAME with a 400 and `INVALID_FIELD`, naming the field and listing the ones that would work — and with NO coverage pointer, because the real API refuses it too and pointing at our manifest would misdirect somebody who needs to look at their own request. A field this replica does not serve at all is the other refusal and does carry the pointer, because the served field list is a subset of the real object's. A value that is not unique on its field answers Salesforce's own 300 with the matching record paths, rather than the first match", mode_reviewed: "2026-09-12", tag: "sObject Rows" }
      - { method: "GET", path: "/services/data/{version}/sobjects/{sObject}/{id}", area: "sobject-rows", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED. Every field is read out of the artifact's CRM tables; the 18-character Id is derived from the CANONICAL id (never from a row's position, so an id does not move when a company is inserted ahead of it) with Salesforce's own published case-safe checksum, checked in ids.test.ts against Salesforce's published 15->18 pairs. Both id lengths are accepted the way the real API accepts them and the 18-character form is always returned. A field with no canon value serves an explicit null rather than being omitted — the opposite of this fleet's usual rule, because Salesforce does the opposite and `record.Phone` is a property access in every client ever written. A well-formed id that names nothing is a DATA 404 with NO coverage pointer, which is the other 404 and a different statement", mode_reviewed: "2026-09-04", tag: "sObject Rows" }
      - { method: "GET", path: "/services/data/{version}/sobjects/{sObject}/{id}/{relationshipFieldName}", area: "sobject-rows", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED (wave W5): a parent traversal reads the PARENT RECORD, and every foreign key it walks was already served — Contact.AccountId, Case.AccountId, Case.ContactId and Contact.ReportsToId all name objects this host describes and projects. Conformance walks EVERY non-null reference on all four objects and asserts the traversal answers byte-identically to fetching that parent by Id, which is invariant #5 at the one route whose whole job is to follow a reference. Three branches are decisions rather than plumbing: a relationship name the object does not have is a plain 400 naming the ones it does (callers most often write the FIELD name, `AccountId`, where the API wants the RELATIONSHIP name, `Account`); `OwnerId` references `User`, which is not among the four founder-scoped objects, so `Owner` answers the coverage 404 until a User sObject ships; and a reference that is NULL answers 204 No Content, because the record was found and the relationship is empty, which is a different statement from `no such record`. THE PATH SHAPE IS SHARED with the external-id retrieve and is disambiguated the way the real API does it — whether the middle segment is a well-formed Salesforce id whose key prefix is this object's", mode_reviewed: "2026-09-12", tag: "sObject Rows" }
      - { method: "GET", path: "/services/data/{version}/sobjects/{sObject}/deleted", area: "change-tracking", tier: 2, status: "green", mode: "empty", mode_reason: "nothing in this universe is ever deleted - the generator writes an append-only event log, this replica accepts no writes, and IsDeleted is false on every record the describe publishes (renderer-salesforce/src/sobjects.ts:472); Salesforce's own answer for a window with no deletions is {\"deletedRecords\": [], \"earliestDateAvailable\": ..., \"latestDateCovered\": ...} at 200. RULED by the founder 2026-09-12 (round 19), coverage wave W5. `earliestDateAvailable` is the instant this snapshot's history of the object begins - the earliest CreatedDate among its records - because this replica's horizon is the artifact's own history rather than the rolling 30-day retention real Salesforce reports there; reporting a retention window this host does not implement would be the invention", mode_reviewed: "2026-09-12", tag: "sObject Change Tracking" }
      - { method: "GET", path: "/services/data/{version}/sobjects/{sObject}/describe", area: "sobject-describe", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED for Account, Contact, Opportunity and Case — the founder-scoped core. The field list is not assembled from recollection: it is GENERATED from the same served-field table the record projection and the SOQL name resolver read, so describe cannot advertise a field a record does not carry or omit one a query would accept. Picklist values are derived from the canon enums' projection tables, so the metadata cannot offer a value no row could hold; child relationships are declared only where the child really carries the foreign key. Every write flag is false because that is TRUE of a read-only replica, which is what lets a client discover the boundary without hitting it. An sObject outside the four answers the coverage 404 — a real org has Leads and we have not built them, and the 404 says which of those two it means", mode_reviewed: "2026-09-04", tag: "sObject Describe" }
      - { method: "GET", path: "/services/data/{version}/sobjects/{sObject}/describe/approvalLayouts", area: "sobject-describe", tier: 1, status: "green", mode: "empty", mode_reason: "no approval process is defined on any served object, so no object has an approval layout - the same fact /process/approvals states; Salesforce's own answer for an object with none is {\"approvalLayouts\": []} at 200. RULED by the founder 2026-09-12 (round 19), coverage wave W5. This row is different IN KIND from its two siblings, which is why it could be ruled while they stay `generate`: `compactLayouts` and `layouts` need a CompactLayout and a PageLayout entity nobody has built, so their emptiness would be a claim about what this replica has not modelled, whereas an approval layout exists PER APPROVAL PROCESS and there is no approval process for one to belong to", mode_reviewed: "2026-09-12", tag: "sObject Describe" }
      - { method: "GET", path: "/services/data/{version}/sobjects/{sObject}/describe/compactLayouts", area: "sobject-describe", tier: 1, status: "planned", mode: "generate", mode_reason: "a compact layout is ORG UI CONFIGURATION — the field set a record's highlights panel shows, per record type — and canon models no layout of any kind; the describe this host serves reports `compactLayoutable: false` for exactly that reason. New canon entity CompactLayout. Nothing about a generation blocks it: the four sObjects are described today", mode_reviewed: "2026-09-08", tag: "sObject Describe" }
      - { method: "GET", path: "/services/data/{version}/sobjects/{sObject}/describe/layouts", area: "sobject-describe", tier: 1, status: "planned", mode: "generate", mode_reason: "a page layout is ORG UI CONFIGURATION — field sections, related lists, buttons, and the record-type and profile assignments that decide which layout a user gets — and canon models none of it; the describe this host serves reports `layoutable: false` for exactly that reason. New canon entities PageLayout and PageLayoutAssignment. Nothing about a generation blocks it: the four sObjects are described today", mode_reviewed: "2026-09-08", tag: "sObject Describe" }
      - { method: "GET", path: "/services/data/{version}/sobjects/{sObject}/listviews", area: "list-views", tier: 2, status: "deferred", mode: "generate", mode_reason: "a list view is org configuration plus the records it selects — both are CRM canon (hello-14)", mode_reviewed: "2026-09-04", tag: "sObject List Views" }
      - { method: "GET", path: "/services/data/{version}/sobjects/{sObject}/listviews/{listViewId}", area: "list-views", tier: 2, status: "deferred", mode: "generate", mode_reason: "a list view is org configuration plus the records it selects — both are CRM canon (hello-14)", mode_reviewed: "2026-09-04", tag: "sObject List Views" }
      - { method: "GET", path: "/services/data/{version}/sobjects/{sObject}/listviews/{listViewId}/describe", area: "list-views", tier: 2, status: "deferred", mode: "generate", mode_reason: "a list view is org configuration plus the records it selects — both are CRM canon (hello-14)", mode_reviewed: "2026-09-04", tag: "sObject List Views" }
      - { method: "GET", path: "/services/data/{version}/sobjects/{sObject}/listviews/{listViewId}/results", area: "list-views", tier: 2, status: "deferred", mode: "generate", mode_reason: "a list view is org configuration plus the records it selects — both are CRM canon (hello-14)", mode_reviewed: "2026-09-04", tag: "sObject List Views" }
      - { method: "GET", path: "/services/data/{version}/sobjects/{sObject}/quickActions", area: "sobject-describe", tier: 1, status: "planned", mode: "generate", mode_reason: "a quick action is ORG UI CONFIGURATION — the create, update and log-a-call actions an admin defines on an object — and canon models none of them. New canon entity QuickAction. READ-ONLY IS NOT THE BLOCKER: reading an action's DEFINITION is not performing it, and this host would report one the way the describe already reports `createable: false`. Nothing about a generation blocks it: the four sObjects are described today", mode_reviewed: "2026-09-08", tag: "sObject Describe" }
      - { method: "GET", path: "/services/data/{version}/sobjects/{sObject}/updated", area: "change-tracking", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED (wave W5). The blocker this row named — `computed over record history, which the CRM canon has to carry` — was cleared by hello-14: every served table carries `updated_epoch`, which is the SAME column `auditFields` in sobjects.ts publishes as LastModifiedDate and SystemModstamp, so the window is a filter over a field this host already serves rather than a history it has to invent. Conformance asserts the window against the equivalent `WHERE LastModifiedDate >= …` SOQL query, so if a later change points one of them at CreatedDate the two stop agreeing. `start` and `end` must carry an EXPLICIT UTC offset, which is a determinism rule rather than pedantry: `Date.parse` resolves an offsetless dateTime against the runtime's local zone, so the same window would select different records on different machines and `pnpm determinism` — which byte-compares artifacts, not renderer output — could not catch it. Salesforce's 30-day retention horizon is deliberately NOT enforced: this replica has no rolling retention, and `/deleted` reports the horizon it does have instead", mode_reviewed: "2026-09-12", tag: "sObject Change Tracking" }
      - { method: "GET", path: "/services/data/{version}/tabs", area: "ui-metadata", tier: 3, status: "deferred", mode: "generate", mode_reason: "tabs, theme, recently-viewed and the app menu are per-org and per-USER state; nothing in this universe carries a Salesforce user's recent-item list yet", mode_reviewed: "2026-09-04", tag: "User Interface" }
      - { method: "GET", path: "/services/data/{version}/theme", area: "ui-metadata", tier: 3, status: "deferred", mode: "generate", mode_reason: "tabs, theme, recently-viewed and the app menu are per-org and per-USER state; nothing in this universe carries a Salesforce user's recent-item list yet", mode_reviewed: "2026-09-04", tag: "User Interface" }
    graphql: [] # no GraphQL API exists for this provider (REST-only)
  hubspot:
    rest:
      - { method: "GET", path: "/crm-object-schemas/v3/schemas", area: "object-schemas", tier: 2, status: "green", mode: "empty", mode_reason: "SERVED, and the empty SURVIVED the CRM canon — which is the re-review the prep wave owed this one (review §3: 'if hello-14 introduces a custom object type for olympus-labs, this row becomes derive and the empty is wrong'). It did not. This endpoint lists CUSTOM object schemas, and the document says so three times over — the operation summary is 'Retrieve all custom object schemas.', the single read's is 'Retrieve the schema of a specified custom object.', and info.x-hubspot-introduction reads 'Use the custom objects schema API to define new types of CRM records in your account.' hello-14 adds STANDARD objects (companies, contacts, deals, tickets), which this API never lists. So the empty is true, it is true for a reason that does not expire, and conformance.test.ts now asserts BOTH halves: that the CRM is demonstrably non-empty on this artifact and that this list still is", mode_reviewed: "2026-09-04", tag: "schemas/Basic" }
      - { method: "GET", path: "/crm-object-schemas/v3/schemas/{objectType}", area: "object-schemas", tier: 2, status: "deferred", mode: "refuse", mode_reason: "SERVED as HubSpot's own not-found, which is the truthful answer for every object type a caller can name here. olympus-labs defines no CUSTOM object types, so there is no schema to fetch; and a STANDARD type (companies, contacts, deals, tickets) is refused too, for the same reason the collection above does not list one — this is the custom-object API. The prep wave left this `generate` because 'the shape of that 404 is not settled'; it is settled the way every other refusal on this host is, in HubSpot's own Error envelope, and it carries NO coverage header because the endpoint IS served and the schema is what does not exist", mode_reviewed: "2026-09-04", tag: "schemas/Basic" }
      - { method: "POST", path: "/crm-object-schemas/v3/schemas/batch/read", area: "object-schemas", tier: 2, status: "green", mode: "empty", mode_reason: "SERVED. The batch reader returns the subset of the requested CUSTOM object schemas that exist, and none of them ever does — the same non-expiring fact behind the collection row above, read with a request body instead of a query. `inputs: []` and `inputs` naming types that were never defined both answer the same empty `results`", mode_reviewed: "2026-09-04", tag: "schemas/Batch" }
      - { method: "GET", path: "/crm/v3/objects/0-3", area: "deals", tier: 1, status: "green", mode: "derive", mode_reason: "deals, from the hello-14 CRM canon. The path reads `0-3` rather than `deals` because that is how HubSpot's own pinned document writes the object type — upstream's asymmetry, carried rather than corrected, and the `deals` spelling real HubSpot also answers is deliberately NOT served (no vendored document declares it)", mode_reviewed: "2026-09-04", tag: "deals/Basic" }
      - { method: "GET", path: "/crm/v3/objects/0-3/{dealId}", area: "deals", tier: 1, status: "green", mode: "derive", tag: "deals/Basic" }
      - { method: "POST", path: "/crm/v3/objects/0-3/batch/read", area: "deals-batch", tier: 2, status: "green", mode: "derive", tag: "deals/Batch" }
      - { method: "POST", path: "/crm/v3/objects/0-3/search", area: "deals", tier: 1, status: "green", mode: "derive", tag: "deals/Search" }
      - { method: "GET", path: "/crm/v3/objects/companies", area: "companies", tier: 1, status: "green", mode: "derive", tag: "companies/Basic" }
      - { method: "GET", path: "/crm/v3/objects/companies/{companyId}", area: "companies", tier: 1, status: "green", mode: "derive", tag: "companies/Basic" }
      - { method: "POST", path: "/crm/v3/objects/companies/batch/read", area: "companies-batch", tier: 2, status: "green", mode: "derive", tag: "companies/Batch" }
      - { method: "POST", path: "/crm/v3/objects/companies/search", area: "companies", tier: 1, status: "green", mode: "derive", mode_reason: "search is a READ HubSpot expresses as a POST, because its criteria are a document rather than a query string. All thirteen Filter.operator members, both filter-group levels, `query`, `sorts` and cursor paging are evaluated against the property map each record renders to — the same map the object read serves, so a filter written against what a caller can see selects what a caller expects", mode_reviewed: "2026-09-04", tag: "companies/Search" }
      - { method: "GET", path: "/crm/v3/objects/contacts", area: "contacts", tier: 1, status: "green", mode: "derive", tag: "contacts/Basic" }
      - { method: "GET", path: "/crm/v3/objects/contacts/{contactId}", area: "contacts", tier: 1, status: "green", mode: "derive", tag: "contacts/Basic" }
      - { method: "POST", path: "/crm/v3/objects/contacts/batch/read", area: "contacts-batch", tier: 2, status: "green", mode: "derive", tag: "contacts/Batch" }
      - { method: "POST", path: "/crm/v3/objects/contacts/search", area: "contacts", tier: 1, status: "green", mode: "derive", tag: "contacts/Search" }
      - { method: "GET", path: "/crm/v3/objects/tickets", area: "tickets", tier: 1, status: "green", mode: "derive", tag: "tickets/Basic" }
      - { method: "GET", path: "/crm/v3/objects/tickets/{ticketId}", area: "tickets", tier: 1, status: "green", mode: "derive", tag: "tickets/Basic" }
      - { method: "POST", path: "/crm/v3/objects/tickets/batch/read", area: "tickets-batch", tier: 2, status: "green", mode: "derive", tag: "tickets/Batch" }
      - { method: "POST", path: "/crm/v3/objects/tickets/search", area: "tickets", tier: 1, status: "green", mode: "derive", tag: "tickets/Search" }
      - { method: "GET", path: "/crm/v3/owners", area: "owners", tier: 1, status: "green", mode: "derive", mode_reason: "the go-to-market roster, and the identity join review §8.2 called the serving wave's second deliverable: every CRM record's hubspot_owner_id resolves to an owner whose email is a canonical person's, and parity/hubspot-crm-parity.test.ts walks that join through the hosts rather than through the artifact", mode_reviewed: "2026-09-04", tag: "owners/Basic" }
      - { method: "GET", path: "/crm/v3/owners/{ownerId}", area: "owners", tier: 1, status: "green", mode: "derive", tag: "owners/Basic" }
      - { method: "GET", path: "/crm/v3/pipelines/{objectType}", area: "pipelines", tier: 2, status: "green", mode: "derive", mode_reason: "the deal and ticket stage vocabularies. Derived from canon's own DEAL_PIPELINE and TicketStatus sets rather than from artifact rows — a pipeline is org configuration, not simulation output, which is exactly why canon holds it as a static table. Projected into renderer-hubspot/src/pipelines.ts because no renderer in this fleet depends on @sandboxapis/canon, and held to canon stage-for-stage by conformance", mode_reviewed: "2026-09-04", tag: "pipelines/Basic" }
      - { method: "GET", path: "/crm/v3/pipelines/{objectType}/{pipelineId}", area: "pipelines", tier: 2, status: "green", mode: "derive", tag: "pipelines/Basic" }
      - { method: "GET", path: "/crm/v3/pipelines/{objectType}/{pipelineId}/audit", area: "pipelines", tier: 2, status: "green", mode: "empty", mode_reason: "SERVED. A pipeline audit lists the CHANGES made to a pipeline, and nothing in this simulation ever edits one: canon's DEAL_PIPELINE is a static table precisely so a deal's probability cannot move under a pinned customer, and the ticket statuses are Zendesk's fixed six. Both pipelines are the portal's DEFAULT pipelines — the document's own `createdAt = 0` case — and an unedited default pipeline has an empty audit trail upstream too. This is not difficulty laundered as coverage: there is no audit canon being withheld, and the day the simulation grows pipeline editing the row goes red rather than hiding it", mode_reviewed: "2026-09-04", tag: "pipelines/Basic" }
      - { method: "GET", path: "/crm/v3/pipelines/{objectType}/{pipelineId}/stages", area: "pipelines", tier: 2, status: "green", mode: "derive", tag: "pipelines/Basic" }
      - { method: "GET", path: "/crm/v3/pipelines/{objectType}/{pipelineId}/stages/{stageId}", area: "pipelines", tier: 2, status: "green", mode: "derive", tag: "pipelines/Basic" }
      - { method: "GET", path: "/crm/v3/pipelines/{objectType}/{pipelineId}/stages/{stageId}/audit", area: "pipelines", tier: 2, status: "green", mode: "empty", mode_reason: "SERVED, for exactly the reason the pipeline audit above is: a stage on an unedited default pipeline has no recorded changes. The two rows are one fact read at two granularities, and both go red together the day pipeline editing enters the simulation", mode_reviewed: "2026-09-04", tag: "pipelines/Basic" }
      - { method: "GET", path: "/crm/v3/properties/{objectType}", area: "properties", tier: 1, status: "green", mode: "derive", mode_reason: "the property catalogue. The prep wave left this `generate` because 'the pinned documents declare the SHAPE of a property and never the default LIST, so serving one now would mean publishing a catalogue transcribed from memory'. That objection is answered rather than waived: the catalogue is olympus-labs' OWN, derived from canon's columns, and every enumerated property DECLARES its vocabulary in its own `options` — which is how a real HubSpot portal works, since option sets are per-portal configuration. The one thing that IS transcribed from the document is the DEFAULT property set, which each of the four object documents prints in info.description as a table ('Properties returned by default')", mode_reviewed: "2026-09-04", tag: "properties/Core" }
      - { method: "GET", path: "/crm/v3/properties/{objectType}/{propertyName}", area: "properties", tier: 1, status: "green", mode: "derive", tag: "properties/Core" }
      - { method: "POST", path: "/crm/v3/properties/{objectType}/batch/read", area: "properties-batch", tier: 2, status: "green", mode: "derive", tag: "properties/Batch" }
      - { method: "GET", path: "/crm/v3/properties/{objectType}/groups", area: "property-groups", tier: 2, status: "green", mode: "derive", tag: "properties/Basic" }
      - { method: "GET", path: "/crm/v3/properties/{objectType}/groups/{groupName}", area: "property-groups", tier: 2, status: "green", mode: "derive", tag: "properties/Basic" }
    graphql: [] # no GraphQL API exists for this provider (REST-only)
  buildkite:
    rest:
      - { method: "GET", path: "/", area: "meta", tier: 1, status: "green", mode: "derive", tag: "root" }
      - { method: "GET", path: "/v2/access-token", area: "access-token", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (wave W6): the token the caller authenticated with - reader.getPersonByLogin(\"athena\") + credentialsForPerson(id, 'personal-token'), the viewer's own ACTIVE row. This replica accepts any credential or none (the standing posture), so what this describes is not the bytes the caller sent but the token the VIEWER really holds in the artifact - the same substitution GET /v2/user makes for the account, and the only honest reading available. uuid/scopes/description/created_at/expires_at/user all read off columns; the canon TokenScope -> Buildkite scope spelling is the per-renderer mapping renderer-github/src/render-credentials.ts:198 established, total over the canon enum and explicit about the six scopes that name resources the Pipelines API does not have (repository, issue, package), which are DROPPED rather than invented. created_at is rendered ISO rather than the document example's \"2025-07-16 06:07:42 UTC\", the fleet decision render.ts `iso` already records. GATED on hasCredentials(): person_credential is hello-16 canon, so an older artifact answers the generation gap naming hello-16 rather than a 404 that would read as 'no such endpoint'", mode_reviewed: "2026-09-12", tag: "access-token" }
      - { method: "GET", path: "/v2/builds", area: "builds", tier: 1, status: "green", mode: "derive", tag: "builds" }
      - { method: "GET", path: "/v2/meta", area: "meta", tier: 1, status: "green", mode: "derive", tag: "meta" }
      - { method: "GET", path: "/v2/organizations", area: "organizations", tier: 1, status: "green", mode: "derive", tag: "organizations" }
      - { method: "GET", path: "/v2/organizations/{org.slug}", area: "organizations", tier: 1, status: "green", mode: "derive", tag: "organizations" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/agents", area: "agents", tier: 2, status: "green", mode: "empty", mode_reason: "Buildkite documents List agents as returning only an organization's CONNECTED AND STOPPING agents. An agent is connected because a build is in flight, and no build here is: every canonical run and job concludes success or failure, and the renderer serves all of them in Buildkite's terminal passed/failed/canceled — never running or scheduled. This canon carries no CI runner entity at all, so `[]` withholds nothing (founder ruling 2026-09-05)", mode_reviewed: "2026-09-05", tag: "agents" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/agents/{id}", area: "agents", tier: 2, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the honest empty beside it: GET .../agents serves `[]` on this same host (Buildkite documents List agents as returning only CONNECTED AND STOPPING agents, and no build in this universe is in flight), so no id can name an agent and Buildkite's own not-found is the whole answer. The status and the body are BOTH the document's rather than derived - getAgent declares its own 404 against the Error envelope, and the literal `{\"message\":\"No agent found\"}` is published twice on the same resource's pause and resume operations - which makes this the one Buildkite refusal whose sentence was neither authored nor truncated. Left unclassified by the 2026-09-05 refuse wave because it arrived after that wave's three families were scoped; a refusal entailed by a served answer cannot drift (founder ruling 2026-09-06, coverage/reviews/2026-09-06-zendesk-rulings.md)", mode_reviewed: "2026-09-06", tag: "agents" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/api-settings", area: "organization-settings", tier: 3, status: "deferred", mode: "refuse", mode_reason: "organization ADMINISTRATORS only, and the sentence is the vendored page's rather than ours: docs/rest_api__organizations__api_settings.md says in as many words that \"These endpoints require a read_organization_settings or write_organization_settings access token scope, and the authenticated user must be a Buildkite organization administrator\", and its own 403 row states the condition this host serves back - \"The token does not have the read_organization_settings scope, or the authenticated user is not an organization administrator.\" The viewer this replica authenticates as holds athena's personal token and neither that scope nor that role, and canon holds no organization-settings entity either - so even an administrator's token would have nothing to report here. The entitlement-gate class this fence already had ten rows of, with a DOCUMENTED sentence rather than an authored one. RULED by the founder 2026-09-14 on the unjudged-47 pass's proposal, as proposed.", mode_reviewed: "2026-09-14", tag: "organization-settings" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/audit_events", area: "audit-events", tier: 3, status: "deferred", mode: "refuse", mode_reason: "ENTERPRISE PLAN, and this is the row whose blocker moved furthest. The shape is in hand (AuditEventPage, a fourth cursor family, vendored 2026-09-12) and canon HOLDS audit rows - reader.listAuditEvents(), 14 fields, true on the current pins - so the obvious reading was to serve it. The page forbids exactly that: docs/rest_api__organizations__audit_events.md says \"The audit log is only available to Buildkite customers on the Enterprise plan, and is only accessible to Buildkite organization administrators\", and both operations publish a 403 whose condition it states itself - \"The organization's plan does not include audit logging, the user cannot view the audit log, or the token does not have the read_audit_events scope.\" Serving canon's audit rows here would assert an Enterprise plan olympus-labs does not have, which is a claim about the UNIVERSE rather than a gap in it. RULED by the founder 2026-09-14 on the unjudged-47 pass's proposal, as proposed.", mode_reviewed: "2026-09-14", tag: "audit-events" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/audit_events/{uuid}", area: "audit-events", tier: 3, status: "deferred", mode: "refuse", mode_reason: "the same documented 403, on the same page, for the same operation family - the by-uuid read publishes it verbatim beside the list's. NOT entailed by the row beside it, and the distinction is worth keeping: the list is REFUSED rather than empty, so it entails nothing at all, and this row is gated in its own right by the same Enterprise-plan sentence. RULED by the founder 2026-09-14 on the unjudged-47 pass's proposal, as proposed.", mode_reviewed: "2026-09-14", tag: "audit-events" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/builds", area: "builds", tier: 1, status: "green", mode: "derive", tag: "builds" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/clusters", area: "clusters", tier: 3, status: "green", mode: "empty", mode_reason: "olympus-labs defines no Buildkite cluster - a cluster is an isolated set of AGENTS and pipelines, this canon carries no runner entity at all (the founder's 2026-09-05 agents ruling, which serves `[]` from this same host), and the pipeline objects this host serves deliberately omit `cluster_id`; Buildkite's own answer for an organization with no cluster is `[]` at 200. RULED by the founder 2026-09-12 (round 19), on the coverage audit's proposal", mode_reviewed: "2026-09-12", tag: "clusters" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/clusters/{cluster.id}/agent-images", area: "clusters", tier: 3, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the empty beside it: .../clusters serves `[]` on this same host, so no cluster id resolves and every sub-resource under it is Buildkite's own not-found (the agents/{id} precedent); the operation declares only a 200, so the body is Buildkite's documented `{\"message\": ...}` envelope per REFUSE_SHAPES.md's nearest-published rule - which is also why refusal is the only terminal option here, the 200 shape being undocumented. RULED by the founder 2026-09-12 (round 19), on the coverage audit's proposal", mode_reviewed: "2026-09-12", tag: "clusters" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/clusters/{cluster.id}/agent-images/{id}", area: "clusters", tier: 3, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the empty beside it: .../clusters serves `[]` on this same host, so no cluster id resolves and every sub-resource under it is Buildkite's own not-found (the agents/{id} precedent); the operation declares only a 200, so the body is Buildkite's documented `{\"message\": ...}` envelope per REFUSE_SHAPES.md's nearest-published rule - which is also why refusal is the only terminal option here, the 200 shape being undocumented. RULED by the founder 2026-09-12 (round 19), on the coverage audit's proposal", mode_reviewed: "2026-09-12", tag: "clusters" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/clusters/{cluster.id}/cache_volumes", area: "clusters", tier: 3, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the empty beside it: .../clusters serves `[]` on this same host, so no cluster id resolves and every sub-resource under it is Buildkite's own not-found (the agents/{id} precedent); the operation declares only a 200, so the body is Buildkite's documented `{\"message\": ...}` envelope per REFUSE_SHAPES.md's nearest-published rule - which is also why refusal is the only terminal option here, the 200 shape being undocumented. RULED by the founder 2026-09-12 (round 19), on the coverage audit's proposal", mode_reviewed: "2026-09-12", tag: "clusters" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/clusters/{cluster.id}/network_ranges", area: "clusters", tier: 3, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the empty beside it: .../clusters serves `[]` on this same host, so no cluster id resolves and every sub-resource under it is Buildkite's own not-found (the agents/{id} precedent); the operation declares only a 200, so the body is Buildkite's documented `{\"message\": ...}` envelope per REFUSE_SHAPES.md's nearest-published rule - which is also why refusal is the only terminal option here, the 200 shape being undocumented. RULED by the founder 2026-09-12 (round 19), on the coverage audit's proposal", mode_reviewed: "2026-09-12", tag: "clusters" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/clusters/{cluster.id}/queues", area: "clusters", tier: 3, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the empty beside it: .../clusters serves `[]` on this same host, so no cluster id resolves and every sub-resource under it is Buildkite's own not-found (the agents/{id} precedent); the operation declares only a 200, so the body is Buildkite's documented `{\"message\": ...}` envelope per REFUSE_SHAPES.md's nearest-published rule - which is also why refusal is the only terminal option here, the 200 shape being undocumented. RULED by the founder 2026-09-12 (round 19), on the coverage audit's proposal", mode_reviewed: "2026-09-12", tag: "clusters" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/clusters/{cluster.id}/queues/{id}", area: "clusters", tier: 3, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the empty beside it: .../clusters serves `[]` on this same host, so no cluster id resolves and every sub-resource under it is Buildkite's own not-found (the agents/{id} precedent); the operation declares only a 200, so the body is Buildkite's documented `{\"message\": ...}` envelope per REFUSE_SHAPES.md's nearest-published rule - which is also why refusal is the only terminal option here, the 200 shape being undocumented. RULED by the founder 2026-09-12 (round 19), on the coverage audit's proposal", mode_reviewed: "2026-09-12", tag: "clusters" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/clusters/{cluster.id}/tokens", area: "clusters", tier: 3, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the empty beside it: .../clusters serves `[]` on this same host, so no cluster id resolves and every sub-resource under it is Buildkite's own not-found (the agents/{id} precedent); the operation declares only a 200, so the body is Buildkite's documented `{\"message\": ...}` envelope per REFUSE_SHAPES.md's nearest-published rule - which is also why refusal is the only terminal option here, the 200 shape being undocumented. RULED by the founder 2026-09-12 (round 19), on the coverage audit's proposal", mode_reviewed: "2026-09-12", tag: "clusters" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/clusters/{cluster.id}/tokens/{id}", area: "clusters", tier: 3, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the empty beside it: .../clusters serves `[]` on this same host, so no cluster id resolves and every sub-resource under it is Buildkite's own not-found (the agents/{id} precedent); the operation declares only a 200, so the body is Buildkite's documented `{\"message\": ...}` envelope per REFUSE_SHAPES.md's nearest-published rule - which is also why refusal is the only terminal option here, the 200 shape being undocumented. RULED by the founder 2026-09-12 (round 19), on the coverage audit's proposal", mode_reviewed: "2026-09-12", tag: "clusters" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/clusters/{id}", area: "clusters", tier: 3, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the empty beside it: .../clusters serves `[]` on this same host, so no cluster id resolves and every sub-resource under it is Buildkite's own not-found (the agents/{id} precedent); the operation declares only a 200, so the body is Buildkite's documented `{\"message\": ...}` envelope per REFUSE_SHAPES.md's nearest-published rule - which is also why refusal is the only terminal option here, the 200 shape being undocumented. RULED by the founder 2026-09-12 (round 19), on the coverage audit's proposal", mode_reviewed: "2026-09-12", tag: "clusters" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/emojis", area: "emojis", tier: 2, status: "deferred", mode: "generate", mode_reason: "static provider catalog, and NOT `derive`: `derive` is defined in this file as computed from artifact rows that already exist, and a vendor catalog is not an artifact row. LICENCE: NO GRANT. The catalogue is published in exactly one place, github.com/buildkite/emojis (805 Buildkite entries in img-buildkite-64.json plus 1,900 Apple-derived Unicode entries in img-apple-64.json, 2,705 total); that repository carries no LICENSE, LICENSE.md, LICENSE.txt or COPYING at its default branch, GitHub's own licence detector reports license: null, neither its package.json nor the published npm package @buildkite/emojis@2.0.1009 declares a license field, and its README's entire `## License` section reads \"Each logo is owned by their respective creators\" - a DISCLAIMER of ownership naming third parties as the owners, which is not a grant and leaves none to fall back on. Every `url` value in the vendored example points at buildkiteassets.com, so mirroring the set would also hand our callers somebody else's CDN, the objection already recorded on /v2/meta's webhook_ips. Serving only the six entries the MIT-licensed docs/rest_api__emojis.md happens to quote was considered and rejected: six of 2,705 presented as \"the organization's emojis\" is a false claim about completeness, which is worse than not answering. THE VERDICT IS THE 2026-09-05 ONE, UNCHANGED - a static `derive` ruling conditioned on a provenance check that then FAILED - and the only new thing is that the row now carries the LABEL for it rather than no entry at all, verbatim the classification github's own GET /emojis has held since 2026-09-09. THE FOUNDER'S OPEN QUESTION IS UNTOUCHED: whether to re-rule this `refuse` with the licence as the stated reason. CLASSIFIED 2026-09-13 (the unjudged-47 pass); no number moves, because a held row stays in the badge denominator and out of its numerator", mode_reviewed: "2026-09-13", held: "data-licensing", held_reviewed: "2026-09-13", tag: "emojis" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/jobs/{job.id}", area: "jobs", tier: 1, status: "green", mode: "derive", tag: "jobs" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/jobs/{job.id}/annotations", area: "annotations", tier: 2, status: "green", mode: "empty", mode_reason: "an annotation is uploaded by `buildkite-agent annotate` from inside a job; this canon's jobs carry a log and nothing else, so a job that never ran `annotate` truthfully answers `[]` (founder ruling 2026-09-05)", mode_reviewed: "2026-09-05", tag: "annotations" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/jobs/{job.id}/artifacts", area: "artifacts", tier: 2, status: "green", mode: "derive", mode_reason: "hello-15 + PR C (#383) closed BOTH deferrals this family had. The first, at classification: canon's `Artifact` carried no job link and every Buildkite artifact route is job-scoped - closed by `Artifact.job`. The second, found by the serving wave on 2026-09-07: `sha1sum` is REQUIRED on the `Artifact` schema and EVERY route returning one `$ref`s it, so a row without bytes served nothing, list or show. PR C gave every artifact real TEXT content - a JUnit document built from the run's own TestResult rows, a size report over real blob lengths, an SBOM over the repository's real dependency manifest - with a compiler-MEASURED `size_bytes` and a SHA-1 and SHA-256 of exactly those bytes. Reads `reader.jobArtifacts()`/`reader.runArtifacts()`; `state` is `finished` because every job here completed and really uploaded, and `glob_path`/`original_path` are the null the provider itself sends on two deprecated fields", mode_reviewed: "2026-09-07", tag: "artifacts" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/jobs/{job.id}/artifacts/{id}", area: "artifacts", tier: 2, status: "green", mode: "derive", mode_reason: "the same artifact addressed by id, from `reader.jobArtifacts()`. Buildkite publishes an org-scoped and a build-scoped path to one artifact and the object carries ONE canonical `url` - the build-scoped spelling its own examples print - so a caller cannot see the same artifact claim two different canonical URLs depending on how it was reached", mode_reviewed: "2026-09-07", tag: "artifacts" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/jobs/{job.id}/artifacts/{id}/download", area: "artifacts", tier: 2, status: "green", mode: "derive", mode_reason: "the download, from `reader.artifactContent()` - the bytes PR C composed. MIRRORS THE DOCUMENT EXACTLY: 302, the URL in the `Location` header AND in a one-field JSON body, which is what the page describes (`The URL will be returned in the response body and the Location HTTP header`). The target is a SIGNED path on the service host rather than these bytes served inline: serving 200 here would break every SDK that reads the signed URL with `redirect: manual`, and pointing at buildkiteartifacts.com would send a caller out of the universe to a URL that 404s. It is the founder's 2026-09-02 ruling for GitHub's five 302 operations applied unchanged, and it is also what Buildkite's own sentence describes for a customer using their own bucket", mode_reviewed: "2026-09-07", tag: "artifacts" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/jobs/{job.id}/env", area: "jobs", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (wave W6): the job's environment, which is the build, the job, the pipeline, the organization and the commit FLATTENED - so every key is read off the same derivation the corresponding JSON field uses (BUILDKITE_COMMIT is shapeBuild's `commit`, BUILDKITE_REPO is shapePipeline's `repository`, BUILDKITE_COMMAND is shapeJob's `command`) and a caller that reads a value twice cannot get two answers. The two AGENT keys the documented example prints - BUILDKITE_AGENT_NAME and BUILDKITE_AGENT_META_DATA_LOCAL - are deliberately ABSENT, entailed by the empty agent list this same host serves: a canonical Job records what ran and never what it ran ON, so naming an agent here would contradict the answer beside it. BUILDKITE_TAG and BUILDKITE_ARTIFACT_PATHS are the empty string the provider's own example carries, and BUILDKITE_PULL_REQUEST is the pull's number when the run's commit really belongs to one (pullsForCommit) and the documented \"false\" otherwise. text/plain and the `.txt` suffix serve the documented KEY=VALUE form", mode_reviewed: "2026-09-12", tag: "jobs" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/jobs/{job.id}/log", area: "jobs", tier: 1, status: "green", mode: "derive", tag: "jobs" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/members", area: "organization-members", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (the response-shape wave): the organization roster, from reader.listMemberships('org', org) paired with the people it names. UNBLOCKED BY DOCUMENTATION RATHER THAN BY CANON - the page lives at pages/apis/rest_api/organizations/members.md, a sub-directory the 2026-09-05 wave did not walk, and until it was vendored the evidence set asserted no field names. `id` is the USER's uuid, which the page states outright is what the member's id is, so it is the same uuid /v2/user and every embedded actor already publish for that person; `email` is the fleet's login@<org>.dev convention; `role` collapses canon's five MembershipRoleKeys into Buildkite's CLOSED admin/member enum (owner and admin administer, the rest do not) - the GitHub org-membership.role case rather than the Jira one, and the map lives in one place. `sso_mode` is OMITTED because the page says it is returned only to an organization administrator or on the caller's own membership, and this token is neither. Gated on hasMemberships() (hello-16): an older artifact has the roster but not the seats", mode_reviewed: "2026-09-12", tag: "organization-members" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/members/{user.uuid}", area: "organization-members", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12: the same member by the uuid the roster publishes, from the same pairing. A uuid naming nobody is Buildkite's 404, which the roster entails", mode_reviewed: "2026-09-12", tag: "organization-members" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/pipeline-settings", area: "organization-settings", tier: 3, status: "deferred", mode: "refuse", mode_reason: "organization ADMINISTRATORS only, and this page names the permission outright: docs/rest_api__organizations__pipeline_settings.md says \"Both read and write operations require organization administrator privileges (the change_organization permission)\" - VERBATIM the sentence the three repository-connection refusals on this fence already serve - and its own 403 row states the condition this host serves back, \"The token does not have the read_organization_settings scope, or the authenticated user does not have organization administrator privileges.\" The viewer this replica authenticates as holds athena's personal token and neither that scope nor that role, and canon holds no organization-settings entity either - so even an administrator's token would have nothing to report here. The entitlement-gate class this fence already had ten rows of, with a DOCUMENTED sentence rather than an authored one. RULED by the founder 2026-09-14 on the unjudged-47 pass's proposal, as proposed.", mode_reviewed: "2026-09-14", tag: "organization-settings" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/pipeline-templates", area: "pipeline-templates", tier: 3, status: "deferred", mode: "refuse", mode_reason: "pipeline templates are an Enterprise plan feature - the vendored page opens 'Enterprise plan feature' and 'Pipeline templates are only available on an Enterprise plan' - so olympus-labs is not entitled to this API at all, and Buildkite answers an unentitled caller its own 403 rather than an empty list", mode_reviewed: "2026-09-05", tag: "pipeline-templates" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/pipeline-templates/{uuid}", area: "pipeline-templates", tier: 3, status: "deferred", mode: "refuse", mode_reason: "pipeline templates are an Enterprise plan feature - the vendored page opens 'Enterprise plan feature' and 'Pipeline templates are only available on an Enterprise plan' - so olympus-labs is not entitled to this API at all, and Buildkite answers an unentitled caller its own 403 rather than an empty list", mode_reviewed: "2026-09-05", tag: "pipeline-templates" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/pipelines", area: "pipelines", tier: 1, status: "green", mode: "derive", tag: "pipelines" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/pipelines/{pipeline.slug}", area: "pipelines", tier: 1, status: "green", mode: "derive", tag: "pipelines" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/pipelines/{pipeline.slug}/builds", area: "builds", tier: 1, status: "green", mode: "derive", tag: "builds" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/pipelines/{pipeline.slug}/builds/{build.number}", area: "builds", tier: 1, status: "green", mode: "derive", tag: "builds" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/pipelines/{pipeline.slug}/builds/{build.number}/annotations", area: "annotations", tier: 2, status: "green", mode: "empty", mode_reason: "the build-scoped half of the same fact: no job in this build ever ran `buildkite-agent annotate`, so the build carries no annotation and `[]` is the whole truthful answer (founder ruling 2026-09-05)", mode_reviewed: "2026-09-05", tag: "annotations" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/pipelines/{pipeline.slug}/builds/{build.number}/artifacts", area: "artifacts", tier: 2, status: "green", mode: "derive", mode_reason: "hello-15 + PR C (#383) closed BOTH deferrals this family had. The first, at classification: canon's `Artifact` carried no job link and every Buildkite artifact route is job-scoped - closed by `Artifact.job`. The second, found by the serving wave on 2026-09-07: `sha1sum` is REQUIRED on the `Artifact` schema and EVERY route returning one `$ref`s it, so a row without bytes served nothing, list or show. PR C gave every artifact real TEXT content - a JUnit document built from the run's own TestResult rows, a size report over real blob lengths, an SBOM over the repository's real dependency manifest - with a compiler-MEASURED `size_bytes` and a SHA-1 and SHA-256 of exactly those bytes. Reads `reader.jobArtifacts()`/`reader.runArtifacts()`; `state` is `finished` because every job here completed and really uploaded, and `glob_path`/`original_path` are the null the provider itself sends on two deprecated fields", mode_reviewed: "2026-09-07", tag: "artifacts" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/pipelines/{pipeline.slug}/builds/{build.number}/jobs", area: "jobs", tier: 1, status: "green", mode: "derive", tag: "jobs" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/pipelines/{pipeline.slug}/builds/{build.number}/jobs/{job.id}", area: "jobs", tier: 1, status: "green", mode: "derive", tag: "jobs" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/pipelines/{pipeline.slug}/builds/{build.number}/jobs/{job.id}/annotations", area: "annotations", tier: 2, status: "green", mode: "empty", mode_reason: "the build-scoped route to the same job annotation list Buildkite also publishes org-scoped; both answer `[]` for the same reason, and serving one without the other would make the same fact reachable at one URL and a 404 at the other (founder ruling 2026-09-05)", mode_reviewed: "2026-09-05", tag: "annotations" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/pipelines/{pipeline.slug}/builds/{build.number}/jobs/{job.id}/artifacts", area: "artifacts", tier: 2, status: "green", mode: "derive", mode_reason: "hello-15 + PR C (#383) closed BOTH deferrals this family had. The first, at classification: canon's `Artifact` carried no job link and every Buildkite artifact route is job-scoped - closed by `Artifact.job`. The second, found by the serving wave on 2026-09-07: `sha1sum` is REQUIRED on the `Artifact` schema and EVERY route returning one `$ref`s it, so a row without bytes served nothing, list or show. PR C gave every artifact real TEXT content - a JUnit document built from the run's own TestResult rows, a size report over real blob lengths, an SBOM over the repository's real dependency manifest - with a compiler-MEASURED `size_bytes` and a SHA-1 and SHA-256 of exactly those bytes. Reads `reader.jobArtifacts()`/`reader.runArtifacts()`; `state` is `finished` because every job here completed and really uploaded, and `glob_path`/`original_path` are the null the provider itself sends on two deprecated fields", mode_reviewed: "2026-09-07", tag: "artifacts" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/pipelines/{pipeline.slug}/builds/{build.number}/jobs/{job.id}/artifacts/{id}", area: "artifacts", tier: 2, status: "green", mode: "derive", mode_reason: "the same artifact addressed by id, from `reader.jobArtifacts()`. Buildkite publishes an org-scoped and a build-scoped path to one artifact and the object carries ONE canonical `url` - the build-scoped spelling its own examples print - so a caller cannot see the same artifact claim two different canonical URLs depending on how it was reached", mode_reviewed: "2026-09-07", tag: "artifacts" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/pipelines/{pipeline.slug}/builds/{build.number}/jobs/{job.id}/artifacts/{id}/download", area: "artifacts", tier: 2, status: "green", mode: "derive", mode_reason: "the download, from `reader.artifactContent()` - the bytes PR C composed. MIRRORS THE DOCUMENT EXACTLY: 302, the URL in the `Location` header AND in a one-field JSON body, which is what the page describes (`The URL will be returned in the response body and the Location HTTP header`). The target is a SIGNED path on the service host rather than these bytes served inline: serving 200 here would break every SDK that reads the signed URL with `redirect: manual`, and pointing at buildkiteartifacts.com would send a caller out of the universe to a URL that 404s. It is the founder's 2026-09-02 ruling for GitHub's five 302 operations applied unchanged, and it is also what Buildkite's own sentence describes for a customer using their own bucket", mode_reviewed: "2026-09-07", tag: "artifacts" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/pipelines/{pipeline.slug}/builds/{build.number}/jobs/{job.id}/env", area: "jobs", tier: 1, status: "green", mode: "derive", mode_reason: "the build-scoped twin of the org-scoped row above. Buildkite publishes both spellings and serving one without the other would make the same environment reachable at one URL and a 404 at the other - the pairing rule the log and artifact routes on this host already follow", mode_reviewed: "2026-09-12", tag: "jobs" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/pipelines/{pipeline.slug}/builds/{build.number}/jobs/{job.id}/log", area: "jobs", tier: 1, status: "green", mode: "derive", tag: "jobs" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/pipelines/{pipeline.slug}/builds/{build.number}/step-uploads", area: "step-uploads", tier: 3, status: "green", mode: "empty", mode_reason: "no build in this universe has a step upload - a step upload is a pipeline configuration posted by `buildkite-agent pipeline upload` from inside a job, and this canon's pipelines are STATIC documents (ci_config_document, source and compiled) whose jobs carry a log and nothing else; it is the annotations ruling (2026-09-05) one family along. THE AGE BRANCH IS RULED TOO, because the same operation publishes a second answer: a build past its thirty-day retention lifetime is Buildkite's documented `410 Gone` carrying the document's own wording, and the age is measured from the BUILD'S OWN FINISHING INSTANT against the ARTIFACT'S ANCHOR - this universe's now - never against the wall clock, which would make a pinned host's answer change every day. A ninety-day window therefore partitions this organization's builds: the newest month answers `{items: [], links: ...}` and everything older answers the 410, and both are the provider's own answer to the same request. RULED by the founder 2026-09-12 (round 19), on the coverage audit's proposal", mode_reviewed: "2026-09-12", tag: "step-uploads" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/pipelines/{pipeline.slug}/builds/{build.number}/step-uploads/{uuid}", area: "step-uploads", tier: 3, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the empty beside it: the build's step-upload page is `{items: [], links: ...}`, so no uuid resolves and Buildkite's own not-found is the answer. Its 410 for an expired build is the same operation's other documented refusal and OUTRANKS this one - the guard is about the BUILD, so a caller asking for an upload on a build Buildkite has aged out is told that rather than that no upload matched. The body is the CAPTURED generic `{\"message\":\"Not Found\"}` and not an authored sentence: the page publishes a 404 DESCRIPTION (\"No step upload matches the given UUID for this build\") rather than a body literal, so asserting one would be a claim about a Buildkite string this repository cannot check. RULED by the founder 2026-09-12 (round 19), on the coverage audit's proposal", mode_reviewed: "2026-09-12", tag: "step-uploads" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/pipelines/{pipeline.slug}/github-webhooks", area: "pipelines", tier: 1, status: "planned", mode: "refuse", mode_reason: "olympus-labs is not enrolled in Buildkite's expanded webhook triggers feature, and the vendored page states the consequence in its own words - `These endpoints return 404 Not Found if your organization is not enrolled in the expanded webhook triggers feature` (rest_api__pipelines.md:1437-1438) - so Buildkite's own 404 is the whole answer. The sentence served is that condition, truncated to the disjunct that holds here, which is the transcription-and-truncation rule the repository_connections class already follows. RULED by the founder 2026-09-12 (round 19), on the coverage audit's proposal", mode_reviewed: "2026-09-12", tag: "pipelines" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/pipelines/{pipeline.slug}/schedules", area: "pipeline-schedules", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (wave W6): the pipeline's schedules - reader.listWorkflowSchedules(repo) narrowed to this workflow. All sixteen required fields have sources: label/message from the canonical name and description, cronline a lossless re-encoding of canon's timetable triple (per_hour, hours_of_day, days_of_week) in the crontab syntax the document itself names, branch resolved to the ref this repository really has, commit the document's own HEAD default because canon's schedule names a branch and no revision, created_by the person canon records, pipeline the workflow it starts, env `{}` because the schedule sets none, enabled true because it started real runs (runsForSchedule), and failed_message/failed_at null because no run of it records a scheduling failure. next_build_at is computed from the cronline and the ARTIFACT'S ANCHOR, never Date.now(), so a pinned host answers the same instant forever. The SAME canonical row is a Bitbucket pipeline_schedule and a CircleCI schedule trigger, and the builds it started are the runs GET .../builds already lists. Gated on hasCiConfig(): workflow_schedule is hello-15 canon, so an older artifact answers the generation gap rather than `[]`, which would say a pipeline that really runs nightly runs on demand only", mode_reviewed: "2026-09-12", tag: "pipeline-schedules" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/pipelines/{pipeline.slug}/schedules/{id}", area: "pipeline-schedules", tier: 3, status: "green", mode: "derive", mode_reason: "the same schedule addressed by id, from the same accessor. A uuid that names no schedule on this pipeline is the ordinary not-found", mode_reviewed: "2026-09-12", tag: "pipeline-schedules" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/pipelines/{pipeline.slug}/triggers", area: "pipeline-triggers", tier: 3, status: "deferred", mode: "refuse", mode_reason: "pipeline triggers are a public preview feature whose reads require Full Access to the pipeline (rest_api__pipeline_triggers.md: 'Required permission: Full Access to the pipeline'), which this token does not have; Buildkite answers it the 403 its own pipelines pages exemplify", mode_reviewed: "2026-09-05", tag: "pipeline-triggers" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/pipelines/{pipeline.slug}/triggers/{id}", area: "pipeline-triggers", tier: 3, status: "deferred", mode: "refuse", mode_reason: "pipeline triggers are a public preview feature whose reads require Full Access to the pipeline (rest_api__pipeline_triggers.md: 'Required permission: Full Access to the pipeline'), which this token does not have; Buildkite answers it the 403 its own pipelines pages exemplify", mode_reviewed: "2026-09-05", tag: "pipeline-triggers" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/pipelines/{pipeline.slug}/triggers/{trigger.id}/deliveries", area: "pipeline-triggers", tier: 3, status: "deferred", mode: "refuse", mode_reason: "pipeline trigger deliveries are a public preview feature whose reads require Full Access to the pipeline (rest_api__pipeline_trigger_deliveries.md states it on all three reads), which this token does not have", mode_reviewed: "2026-09-05", tag: "pipeline-trigger-deliveries" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/pipelines/{pipeline.slug}/triggers/{trigger.id}/deliveries/{delivery.id}", area: "pipeline-triggers", tier: 3, status: "deferred", mode: "refuse", mode_reason: "pipeline trigger deliveries are a public preview feature whose reads require Full Access to the pipeline (rest_api__pipeline_trigger_deliveries.md states it on all three reads), which this token does not have", mode_reviewed: "2026-09-05", tag: "pipeline-trigger-deliveries" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/pipelines/{pipeline.slug}/triggers/{trigger.id}/deliveries/{delivery.id}/request", area: "pipeline-triggers", tier: 3, status: "deferred", mode: "refuse", mode_reason: "pipeline trigger deliveries are a public preview feature whose reads require Full Access to the pipeline (rest_api__pipeline_trigger_deliveries.md states it on all three reads), which this token does not have", mode_reviewed: "2026-09-05", tag: "pipeline-trigger-deliveries" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/portals", area: "portals", tier: 3, status: "green", mode: "empty", mode_reason: "no portal is defined in this organization - a portal is a stored GraphQL operation published at an authenticated URL, this replica serves no Buildkite GraphQL surface at all and canon carries no stored query; Buildkite's own answer for an organization with none is `[]` at 200. RULED by the founder 2026-09-12 (round 19), on the coverage audit's proposal", mode_reviewed: "2026-09-12", tag: "portals" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/portals/{portal.slug}", area: "portals", tier: 3, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the empty beside it: .../portals serves `[]`, so no slug resolves and Buildkite's own not-found is the whole answer. The body is the CAPTURED generic `{\"message\":\"Not Found\"}`: the portals page publishes error tables only on its writes, so authoring a sentence would be a claim this repository cannot check. RULED by the founder 2026-09-12 (round 19), on the coverage audit's proposal", mode_reviewed: "2026-09-12", tag: "portals" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/rate_limit", area: "organizations", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-13 on the founder's ruling. THE REST SCOPE IS THE CALLER'S REAL WINDOW - limit and current are the budget the gateway actually enforces for whoever is asking (the anonymous rung for an anonymous caller, their key's rung for a keyed one), handed to the renderer's shape by ProviderDef.rateLimitBody so the body and the `ratelimit-*` headers of the SAME response can never disagree; conformance drives a real gateway and asserts current + remaining == limit on one call. This is the GitHub /rate_limit arrangement applied a second time - the renderer owns the shape, the gateway owns the numbers (2026-08-30). NOT EXEMPT, and that is the one difference from GitHub's twin: real GitHub documents that it excludes its own /rate_limit from the budget, Buildkite's page documents no exemption, and inventing one would be a claim about this provider we cannot support - so the request is charged like any other and the gateway simply does not DEFER that charge on this path. THE GRAPHQL SCOPE IS TRUE ABOUT A SURFACE THIS HOST DOES NOT SERVE: `current` is 0 because NOTHING HAS EVER BEEN DRAWN FROM THAT BUDGET - there is no Buildkite GraphQL API here - and `enforced` is false in the field's own documented sense, because this replica meters no complexity; `limit` is the 50,000 the vendored page's worked example publishes for the organization scope, quoted rather than enforced, and the `enforced: false` beside it is what says so on the wire. Shape from rest_api/organizations/rate_limits.md, vendored at buildkite/docs bcad57cfcdd63b3888570a04781898d1811a5be0. A PROPERTY OF THE CALLER RATHER THAN OF THE WORLD: nothing here reads the artifact, so every generation and all 127 registered pins answer this identically for the same caller and the row carries no generation gate", mode_reviewed: "2026-09-13", tag: "organizations" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/repository_connections", area: "repository-connections", tier: 3, status: "deferred", mode: "refuse", mode_reason: "reading repository connections requires organization-administrator privileges, and the operation's own documented 403 is 'the token does not have the read_organization_repository_connections scope, or the authenticated user does not have the change_organization permission'", mode_reviewed: "2026-09-05", tag: "repository-connections" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/repository_connections/{id}", area: "repository-connections", tier: 3, status: "deferred", mode: "refuse", mode_reason: "reading repository connections requires organization-administrator privileges, and the operation's own documented 403 is 'the token does not have the read_organization_repository_connections scope, or the authenticated user does not have the change_organization permission'", mode_reviewed: "2026-09-05", tag: "repository-connections" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/repository_connections/{id}/repositories", area: "repository-connections", tier: 3, status: "deferred", mode: "refuse", mode_reason: "reading repository connections requires organization-administrator privileges, and the operation's own documented 403 is 'the token does not have the read_organization_repository_connections scope, or the authenticated user does not have the change_organization permission'", mode_reviewed: "2026-09-05", tag: "repository-connections" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/rules", area: "rules", tier: 3, status: "green", mode: "empty", mode_reason: "no rule is defined in this organization - a Buildkite rule grants one pipeline or cluster an action against another (`pipeline.trigger_build.pipeline`), every rule object names a source and target UUID, and this universe has no cluster and no trigger relationship between its three pipelines; Buildkite's own answer for an organization with none is `[]` at 200. RULED by the founder 2026-09-12 (round 19), on the coverage audit's proposal", mode_reviewed: "2026-09-12", tag: "rules" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/rules/{uuid}", area: "rules", tier: 3, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the empty beside it: .../rules serves `[]`, so no uuid resolves. The body is the CAPTURED generic `{\"message\":\"Not Found\"}` - the rules page publishes error tables only on its writes. RULED by the founder 2026-09-12 (round 19), on the coverage audit's proposal", mode_reviewed: "2026-09-12", tag: "rules" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/services", area: "notification-services", tier: 3, status: "green", mode: "empty", mode_reason: "no notification service is configured in this organization - canon carries no Buildkite-scoped notification target (its Slack canon is channels and messages, and its only webhook rows are PagerDuty-scoped), so nothing here forwards build events; an empty array needs no item schema, which is what makes this row terminal despite the undocumented payload. RULED by the founder 2026-09-12 (round 19), on the coverage audit's proposal", mode_reviewed: "2026-09-12", tag: "notification-services" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/services/{uuid}", area: "notification-services", tier: 3, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the empty beside it: .../services serves `[]`, so no uuid resolves - and, like the list, the refusal needs no 200 shape. RULED by the founder 2026-09-12 (round 19), on the coverage audit's proposal", mode_reviewed: "2026-09-12", tag: "notification-services" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/teams", area: "teams", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (wave W6): the organization's four teams - reader.listTeams(), the SAME canonical rows gh., gl., jira. and linear. already serve, which is why refusing the family on Buildkite's own teams PLAN GATE was rejected: the gate is real (rest_api__teams.md:366-372 publishes a 403 reading 'Your plan doesn't include team permissions'), but it is a claim about an ACCOUNT, and nothing this host serves says olympus-labs is on a plan without teams while five other hosts serve its four (invariant #5). THREE JUDGMENTS, STATED: `description` is the same sentence renderer-github composes from the same two columns, so one canonical team has one description across the fleet; `privacy` is `visible`, a translation of the `closed` GitHub already publishes for these teams rather than a new claim; `default` is false on all four and it is a COUNT rather than a constant - Buildkite's own words are 'whether users join this team by default', the largest team here holds five of seventeen members, and conformance re-runs the count. created_at is orgCreatedEpoch() (canon has no team epoch and the generator builds the teams in the same scaffolding pass as the org), and created_by is the founding member, read off the membership ledger's one added_by NULL row where hello-16 canon exists and off the organization's first member otherwise - conformance asserts the two name one person", mode_reviewed: "2026-09-12", tag: "teams" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/teams/{team.uuid}", area: "teams", tier: 2, status: "green", mode: "derive", mode_reason: "the same Team object addressed by uuid, from the same accessor and with the same three judgments", mode_reviewed: "2026-09-12", tag: "teams" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/teams/{team.uuid}/members", area: "teams", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (the response-shape wave): a team's seats, from reader.listMemberships('team', team). THE CANON WAS ALREADY WIRED - reader.teamMembers() has answered the documented user_id filter on /teams since wave W6 - and what was missing was the vendored page (pages/apis/rest_api/teams/members.md). `created_at` is the ASSOCIATION's own instant, which the page states in those words, and it is why this row reads the membership table rather than the bare roster: only membership.added_epoch carries it. `role` collapses canon's five roles into Buildkite's closed member/maintainer enum. Conformance asserts created_at IS added_epoch, so a later wave cannot substitute the person's own first-seen date. Gated on hasMemberships() (hello-16)", mode_reviewed: "2026-09-12", tag: "teams" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/teams/{team.uuid}/members/{user.uuid}", area: "teams", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12: one seat by the uuid the team roster publishes, from the same pairing; a uuid on no seat is Buildkite's 404", mode_reviewed: "2026-09-12", tag: "teams" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/teams/{team.uuid}/pipelines", area: "teams", tier: 2, status: "deferred", mode: "derive", mode_reason: "RE-PRICED 2026-09-13 (the unjudged-47 pass) from the `generate` the 2026-09-13 response-shape wave proposed. THAT WAVE'S PREMISE WAS 'NO TEAM-TO-PIPELINE EDGE IN CANON', AND THE EDGE EXISTS: hello-17's grant rows put a TEAM principal on a repository membership - packages/generator/src/grants.ts:216-229 writes one `maintainer` grant per repository for the team that owns most of its components, and :233-248 a `member` grant for every team that reviews it - and reader.teamGrants('repo', repo) is the accessor that reaches them, the same one renderer-bitbucket/src/app.ts:1529 already serves permissions-config/groups from. A Buildkite pipeline on this host IS a canonical (repo, workflow) pair (renderer-buildkite/src/render.ts:125, listPipelines), so a team's pipelines are the pipelines of the repositories it holds a grant on; `created_at` is the grant's own added_epoch - the ASSOCIATION's instant, exactly as the members rows beside it already read it - and `pipeline_id` and `pipeline_url` are the uuid and URL /pipelines publishes today. DEFERRED RATHER THAN GREEN, on the ADO chartimages precedent that `derive` states where a row is going while `deferred` says it is not built, because TWO JUDGMENTS ARE STILL OWED: whether a team's authority over a REPOSITORY projects onto every pipeline OF that repository, and how canon's five MembershipRoleKeys collapse into Buildkite's closed three-value access_level enum (read_only / build_and_read / manage_build_and_read), the same collapse the members rows made for `role`. It needs the hello-17 generation gate too, for the reason gap.test.ts exists: teamGrants() answers `[]` rather than throwing on an older pin, and an `[]` here would be a plausible lie about the UNIVERSE rather than the truth about a SNAPSHOT", mode_reviewed: "2026-09-13", tag: "teams" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/teams/{team.uuid}/pipelines/{uuid}", area: "teams", tier: 2, status: "deferred", mode: "derive", mode_reason: "one team pipeline by the uuid the list beside it publishes, off the same reader.teamGrants('repo', repo) x listPipelines() fold; a uuid naming no pipeline of that team is Buildkite's 404. RE-PRICED 2026-09-13 with the list - the same edge, the same two owed judgments, the same hello-17 gate", mode_reviewed: "2026-09-13", tag: "teams" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/teams/{team.uuid}/suites", area: "teams", tier: 2, status: "green", mode: "empty", mode_reason: "no team here has a Test Engine suite, and the fact was already on the record rather than found for this ruling: Buildkite Test Engine is a DIFFERENT PRODUCT served under the /v2/analytics prefix, and coverage/provider-pins.yaml states in as many words that this universe has no canon for its suites, tests or runs. Canon's test_case.suite_slot is an attribute OF A CASE - which unit or integration bucket it belongs to - not a Suite entity with a uuid, a name, a slug and a default branch. An organization that has not enabled Test Engine answers the empty page. The TEAM still resolves: a uuid naming no team is Buildkite's 404, not a cheerful `[]`. RULED by the founder 2026-09-12 on the unclassified sweep's proposal, as proposed.", mode_reviewed: "2026-09-12", tag: "teams" }
      - { method: "GET", path: "/v2/organizations/{org.slug}/teams/{team.uuid}/suites/{uuid}", area: "teams", tier: 2, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the empty beside it: the team's suite list serves `[]` on this same host, so no uuid names a suite. CLAUSE WITHDRAWN THE SAME DAY, and recorded rather than quietly deleted: this reason also argued that refusal was the ONLY terminal option because the 200 shape was undocumented. It is documented - rest_api/teams/suites.md was vendored hours later in the response-shape wave, and the spec of record now carries a TeamSuite schema. The refusal stands on the entailment ALONE, which was always the stronger half. The body is the captured generic `{\"message\":\"Not Found\"}` for the reason wave W6's thirteen carry it, and x-sandboxapis-refusal is the wire difference. RULED by the founder 2026-09-12 on the unclassified sweep's proposal, as proposed.", mode_reviewed: "2026-09-12", tag: "teams" }
      - { method: "GET", path: "/v2/user", area: "user", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (wave W6): the account that owns the token - the SAME person gh. answers GET /user with and gl. answers GET /api/v4/user with, so a caller reading its own identity from three of our hosts gets one answer (invariant #5). shapeUser already emits the six required members for every job creator; created_at is reader.personFirstSeen(), the fleet's own 'when this person came into being here' and the derivation Sentry's dateJoined makes for the same people, and avatar_url resolves on this host's own /avatars/{uuid} route", mode_reviewed: "2026-09-12", tag: "user" }
    graphql: [] # no GraphQL API exists for this provider (REST-only)
  statuspage:
    rest:
      - { method: "GET", path: "/organizations/{organization_id}/permissions/{user_id}", area: "users", tier: 3, status: "deviation", mode: "derive", mode_reason: "SERVED 2026-09-12 (wave W6): one member's access across the organization's pages - the SAME user set /organizations/{id}/users serves (org members who are not bots) and both real page ids, so a caller cannot find somebody in one list and be told they do not exist in the other. THE THREE RBAC BOOLEANS ARE OMITTED ON THE DOCUMENT'S OWN SENTENCE: page_configuration, incident_manager and maintenance_manager each carry the description 'This field will only be present if the organization has Role Based Access Control', and this canon models none - emitting them would assert an RBAC organization. STATUS `deviation`, NOT `green`, and the reason is the document rather than us: it types `data.pages` as a single OBJECT and prints an ARRAY of two page entries in its own example three lines below. This organization really has two pages, so one object could not carry the answer; the row mirrors the live API and the example, not the declared type, which is what `deviation` means. The eighth document bug catalogued for this provider", mode_reviewed: "2026-09-12", tag: "users" }
      - { method: "GET", path: "/organizations/{organization_id}/users", area: "users", tier: 3, status: "green", mode: "derive", tag: "users" }
      - { method: "GET", path: "/pages", area: "pages", tier: 1, status: "green", mode: "derive", tag: "pages" }
      - { method: "GET", path: "/pages/{page_id}", area: "pages", tier: 1, status: "green", mode: "derive", tag: "pages" }
      - { method: "GET", path: "/pages/{page_id}/component-groups", area: "component-groups", tier: 2, status: "green", mode: "empty", mode_reason: "this universe has no component group at all - status_page_service carries no group column and renderer-statuspage/src/render.ts already says so in as many words while omitting `group_id` from every served component; Statuspage's own answer for a page with no groups is `[]` at 200. RULED by the founder 2026-09-12 (round 19), on the coverage audit's proposal", mode_reviewed: "2026-09-12", tag: "component groups" }
      - { method: "GET", path: "/pages/{page_id}/component-groups/{id}", area: "component-groups", tier: 2, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the empty beside it: the group list serves `[]` on this same host, so no id resolves and Statuspage's own 404 is the whole answer. The body is the document's own declared 404 description in the captured `{\"error\": ...}` envelope - Statuspage's 404 can never be captured (its auth layer answers 401 before its router), so an authored sentence would be a claim this repository cannot check, and `x-sandboxapis-refusal` is the whole wire difference. RULED by the founder 2026-09-12 (round 19), on the coverage audit's proposal", mode_reviewed: "2026-09-12", tag: "component groups" }
      - { method: "GET", path: "/pages/{page_id}/component-groups/{id}/uptime", area: "component-groups", tier: 2, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the same empty: with no group, there is no group to compute uptime over. Same body and same header as the row above. RULED by the founder 2026-09-12 (round 19), on the coverage audit's proposal", mode_reviewed: "2026-09-12", tag: "component groups" }
      - { method: "GET", path: "/pages/{page_id}/components", area: "components", tier: 1, status: "green", mode: "derive", tag: "components" }
      - { method: "GET", path: "/pages/{page_id}/components/{component_id}", area: "components", tier: 1, status: "green", mode: "derive", tag: "components" }
      - { method: "GET", path: "/pages/{page_id}/components/{component_id}/uptime", area: "components", tier: 1, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (wave W6): the component's uptime, COMPUTED from the page's own incident record rather than stored - the same walk shapeIncidentUpdate already makes to resolve old_status/new_status, with a clock attached: the seconds between consecutive reported_epoch instants are seconds that component spent in the status the earlier update gave it. DOWNTIME IS BOTH KINDS OF OUTAGE, and the rule was chosen for a reason the caller can check: Statuspage publishes uptime_percentage, major_outage and partial_outage and no formula relating them, and its own example (96.67 with partial_outage 0) cannot discriminate - so the rule taken is the one under which the object is SELF-CONSISTENT, and a caller can recompute the percentage from the two second-counts and the range this same response publishes. degraded_performance is not an outage and contributes nothing. The default window is the document's own ninety days ending at the ARTIFACT'S ANCHOR - 'today in the page's time zone' for a frozen universe is the instant it is frozen at - and `start`/`end` are honoured as the partial dates the document describes, with its own clamp warning when an end date is past today and its documented 422 for a range over six calendar months. `related_events` is OMITTED: the document types it as a single object carrying one `id` while describing it as 'Related incidents', and three of this page's posts touch the fixture component - emitting one would be picking and an array would fail the document's own schema. range_start/range_end are full ISO date-times because the field's `format: date-time` is what a generated client enforces, though the example beside it prints a bare date", mode_reviewed: "2026-09-12", tag: "components" }
      - { method: "GET", path: "/pages/{page_id}/incident_templates", area: "incident-templates", tier: 3, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (wave W6): the universe's own three status-update templates - reader.listStatusUpdateTemplates(), the same three renderer-pagerduty publishes, so one canonical template is one template on both hosts. `name` is the label the Templates tab shows and `title` the subject line canon stores; `update_status` is emitted for the two slots that name a Statuspage status exactly (the holding statement is `investigating`, the resolution notice says in its own text that the incident is resolved) and OMITTED for the progress update, whose message renders {{incident.status}} rather than setting one. THE BODY KEEPS ITS PLACEHOLDERS, and that is the wave's one ruling here: canon's template text carries the field keywords template_field publishes, Statuspage's own templates have no interpolation, and resolving is not available because a template is attached to no incident and no component - so there is no incident number and no business service to resolve against. Omitting the body would leave a template with no content; the text is served verbatim and the deviation from Statuspage's plain-text templates is recorded. components/group_id/should_tweet/should_send_notifications are omitted: canon's template names no service, belongs to no group, and this universe has no Twitter integration", mode_reviewed: "2026-09-12", tag: "templates" }
      - { method: "GET", path: "/pages/{page_id}/incidents", area: "incidents", tier: 1, status: "green", mode: "derive", tag: "incidents" }
      - { method: "GET", path: "/pages/{page_id}/incidents/{incident_id}", area: "incidents", tier: 1, status: "green", mode: "derive", tag: "incidents" }
      - { method: "GET", path: "/pages/{page_id}/incidents/{incident_id}/postmortem", area: "incident-postmortem", tier: 2, status: "green", mode: "derive", tag: "incident postmortem" }
      - { method: "GET", path: "/pages/{page_id}/incidents/{incident_id}/subscribers", area: "incident-subscribers", tier: 2, status: "green", mode: "derive", mode_reason: "the canon models subscription scope on a real column (subscribable_kind is one of status_page / status_page_service / status_page_post) and the renderer queries it. As of hello-15 (features.subscriptionStates) this universe EMITS post-scoped subscriptions, so the row answers non-empty rather than the [] the 2026-09-01 note flagged. The founder confirmed derive over empty on 2026-09-06", mode_reviewed: "2026-09-07", tag: "incident subscribers" }
      - { method: "GET", path: "/pages/{page_id}/incidents/{incident_id}/subscribers/{subscriber_id}", area: "incident-subscribers", tier: 2, status: "green", mode: "derive", mode_reason: "SERVED 2026-09-12 (wave W6): one post-scoped subscriber, addressed by id. THE ROUTE WAS ALREADY REGISTERED AND SERVING - its list twin .../subscribers has been `derive` since 2026-09-06 and this by-id row simply had no MODES entry - so the work was a manifest entry plus a conformance assertion. The lookup is scoped to the POST, which is what makes it a different operation from /pages/{page_id}/subscribers/{subscriber_id}: a page-scoped subscriber does not resolve here, and conformance asserts it", mode_reviewed: "2026-09-12", tag: "incident subscribers" }
      - { method: "GET", path: "/pages/{page_id}/incidents/active_maintenance", area: "incidents", tier: 1, status: "green", mode: "derive", tag: "incidents" }
      - { method: "GET", path: "/pages/{page_id}/incidents/scheduled", area: "incidents", tier: 1, status: "green", mode: "derive", tag: "incidents" }
      - { method: "GET", path: "/pages/{page_id}/incidents/unresolved", area: "incidents", tier: 1, status: "green", mode: "derive", tag: "incidents" }
      - { method: "GET", path: "/pages/{page_id}/incidents/upcoming", area: "incidents", tier: 1, status: "green", mode: "derive", tag: "incidents" }
      - { method: "GET", path: "/pages/{page_id}/metrics", area: "metrics", tier: 3, status: "green", mode: "empty", mode_reason: "this status page publishes no metric - Statuspage requires every published metric to belong to a metrics provider and this page has none (the row below); canon's metric_series and sample rows belong to the internal observability canon (metric_series.service names a TECHNICAL service) and no status_page_service publishes one. NOTE the document types this collection as a single `Metric` where the live API returns a list - the sixth of the seven bugs coverage/provider-pins.yaml catalogues for this provider - so the array is the mirror and `[]` is its empty shape either way. RULED by the founder 2026-09-12 (round 19), on the coverage audit's proposal", mode_reviewed: "2026-09-12", tag: "metrics" }
      - { method: "GET", path: "/pages/{page_id}/metrics_providers", area: "metric-providers", tier: 3, status: "green", mode: "empty", mode_reason: "no metrics provider is connected to this page - canon carries no Datadog/Pingdom/New Relic connection and no self-hosted provider row, and without a provider Statuspage can publish no metric at all; its own answer for a page with none is `[]` at 200. RULED by the founder 2026-09-12 (round 19), on the coverage audit's proposal", mode_reviewed: "2026-09-12", tag: "metric providers" }
      - { method: "GET", path: "/pages/{page_id}/metrics_providers/{metrics_provider_id}", area: "metric-providers", tier: 3, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the empty beside it: the provider list serves `[]`, so no provider id resolves. Statuspage's own 404, not the 403 the same operation also declares: that 403 is about a CALLER's authorization, and this ruling is about an object nobody created. RULED by the founder 2026-09-12 (round 19), on the coverage audit's proposal", mode_reviewed: "2026-09-12", tag: "metric providers" }
      - { method: "GET", path: "/pages/{page_id}/metrics_providers/{metrics_provider_id}/metrics", area: "metrics", tier: 3, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the same empty: no provider id resolves, so there is no provider whose metrics could be listed. RULED by the founder 2026-09-12 (round 19), on the coverage audit's proposal", mode_reviewed: "2026-09-12", tag: "metrics" }
      - { method: "GET", path: "/pages/{page_id}/metrics/{metric_id}", area: "metrics", tier: 3, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the empty above: the page publishes no metric, so no metric id resolves and Statuspage's own 404 is the whole answer, in the document's own declared 404 description. RULED by the founder 2026-09-12 (round 19), on the coverage audit's proposal", mode_reviewed: "2026-09-12", tag: "metrics" }
      - { method: "GET", path: "/pages/{page_id}/page_access_groups", area: "page-access-groups", tier: 3, status: "green", mode: "empty", mode_reason: "THIS PAGE IS NOT AUDIENCE-SPECIFIC, and the fact rests on something a caller can already read on this same host rather than on an assertion. The vendored document says it in its own tag prose, twice and in the same words - \"You will need Statuspage to switch your page type to audience-specific before these API endpoints have any effect on your status page\" - and shapePage() publishes viewers_must_be_team_members off canon's status_page.kind, which is Statuspage's TEAM-MEMBERS-ONLY page and a different type from an audience-specific one. Canon carries exactly two page kinds, public and private, and no third. So this page has no page access group - not because the generator forgot a roster, but because the page has no audience to roster. Statuspage's own answer for a page with none is [] at 200. THE PAGE STILL HAS TO RESOLVE: an id this universe does not have is the ordinary entity 404, never a cheerful empty. RULED by the founder 2026-09-14 on the unjudged-47 pass's proposal, as proposed; this SUPERSEDES wave W6's framing of these rows as a canon question.", mode_reviewed: "2026-09-14", tag: "page access groups" }
      - { method: "GET", path: "/pages/{page_id}/page_access_groups/{page_access_group_id}", area: "page-access-groups", tier: 3, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the empty beside it: the group list serves [] on this same host, so no group id resolves and Statuspage's own 404 is the whole answer - the component-groups precedent this fence ruled on 2026-09-12, one family over. The body is the document's own declared 404 description in the captured {\"error\": ...} envelope, and x-sandboxapis-refusal is the whole wire difference. RULED by the founder 2026-09-14 on the unjudged-47 pass's proposal, as proposed.", mode_reviewed: "2026-09-14", tag: "page access groups" }
      - { method: "GET", path: "/pages/{page_id}/page_access_groups/{page_access_group_id}/components", area: "page-access-groups", tier: 3, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the same empty: with no page access group there is no group whose components could be listed. Same body and same header as the row above. RULED by the founder 2026-09-14 on the unjudged-47 pass's proposal, as proposed.", mode_reviewed: "2026-09-14", tag: "page access group components" }
      - { method: "GET", path: "/pages/{page_id}/page_access_users", area: "page-access-users", tier: 3, status: "green", mode: "empty", mode_reason: "THIS PAGE IS NOT AUDIENCE-SPECIFIC, and the fact rests on something a caller can already read on this same host rather than on an assertion. The vendored document says it in its own tag prose, twice and in the same words - \"You will need Statuspage to switch your page type to audience-specific before these API endpoints have any effect on your status page\" - and shapePage() publishes viewers_must_be_team_members off canon's status_page.kind, which is Statuspage's TEAM-MEMBERS-ONLY page and a different type from an audience-specific one. Canon carries exactly two page kinds, public and private, and no third. So nobody logs in to see this status page. The ONE person-to-page link canon does hold is status_page_subscription.person, and it is a NOTIFICATION RECIPIENT off the engineering roster rather than a login-holding viewer - which is exactly why the subscriber rows on this host serve real rows while this one is empty, and the conformance entry asserts BOTH halves on one run so a later wave cannot make the two agree by habit rather than by evidence. Statuspage's own answer for a page with none is [] at 200. RULED by the founder 2026-09-14 on the unjudged-47 pass's proposal, as proposed.", mode_reviewed: "2026-09-14", tag: "page access users" }
      - { method: "GET", path: "/pages/{page_id}/page_access_users/{page_access_user_id}", area: "page-access-users", tier: 3, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the empty beside it: the page-access-user list serves [] on this same host, so no page access user id resolves and Statuspage's own 404 is the whole answer. RULED by the founder 2026-09-14 on the unjudged-47 pass's proposal, as proposed.", mode_reviewed: "2026-09-14", tag: "page access users" }
      - { method: "GET", path: "/pages/{page_id}/page_access_users/{page_access_user_id}/components", area: "page-access-users", tier: 3, status: "deferred", mode: "refuse", mode_reason: "ENTAILED by the same empty: no page access user resolves, so no per-user component list exists to serve. RULED by the founder 2026-09-14 on the unjudged-47 pass's proposal, as proposed.", mode_reviewed: "2026-09-14", tag: "page access user components" }
      - { method: "GET", path: "/pages/{page_id}/page_access_users/{page_access_user_id}/metrics", area: "page-access-users", tier: 3, status: "deferred", mode: "refuse", mode_reason: "ENTAILED TWICE OVER, and both halves are worth stating because either alone would carry it: no page access user resolves, AND /pages/{page_id}/metrics is itself a ruled honest empty on this host (2026-09-12, no metrics provider is connected to this page), so even a user who did resolve could own no metric. RULED by the founder 2026-09-14 on the unjudged-47 pass's proposal, as proposed.", mode_reviewed: "2026-09-14", tag: "page access user metrics" }
      - { method: "GET", path: "/pages/{page_id}/status_embed_config", area: "status-embed-config", tier: 3, status: "deferred", mode: "generate", mode_reason: "A WIDENING, NOT A BUILD, and the one of the eight unjudged Statuspage rows that is NOT the audience question. A status embed config is a page's own PRESENTATION settings - `position`, the corner the iframe sits in, and four colours for the incident and maintenance states - and canon's status_page table carries six columns of which none is presentational (packages/artifact/src/rows.ts:1122: id, kind, name, url, published_epoch, content_seed). Real Statuspage answers 200 here for every page, so neither cheap answer is available: there is no collection to be empty, and a 404 would deny an operation Statuspage serves. The document names no default for any of the five fields and publishes no example, so nothing is derivable and nothing may be authored - the placeholder invariant. The widening is five columns on status_page, themed at compile time like every other page string. It unblocks ONE row, on this provider only: no other host in the fleet publishes an embed configuration. CLASSIFIED 2026-09-13 (the unjudged-47 pass); the 2026-09-12 W6 fence grouped it with the seven page-access rows as \"one canon question\", and it is a different one", mode_reviewed: "2026-09-13", tag: "status embed config" }
      - { method: "GET", path: "/pages/{page_id}/subscribers", area: "subscribers", tier: 2, status: "green", mode: "derive", tag: "subscribers" }
      - { method: "GET", path: "/pages/{page_id}/subscribers/{subscriber_id}", area: "subscribers", tier: 2, status: "green", mode: "derive", tag: "subscribers" }
      - { method: "GET", path: "/pages/{page_id}/subscribers/count", area: "subscribers", tier: 2, status: "green", mode: "derive", tag: "subscribers" }
      - { method: "GET", path: "/pages/{page_id}/subscribers/histogram_by_state", area: "subscribers", tier: 2, status: "green", mode: "derive", tag: "subscribers" }
      - { method: "GET", path: "/pages/{page_id}/subscribers/unsubscribed", area: "subscribers", tier: 2, status: "green", mode: "derive", mode_reason: "StatusPageSubscription.status carries \"unsubscribed\" as of hello-15 (features.subscriptionStates, the founder's 2026-09-06 ruling), with unsubscribed_epoch for the instant. This serves exactly the rows subscribed() excludes from the list, the count, the histogram and the by-id lookup, because Statuspage's own state filter is closed at active/unconfirmed/quarantined and gives a departed subscriber their own collection instead of a fourth state. A pre-hello-15 artifact answers the generation gap, not [], which would assert that nobody in a universe that cannot represent unsubscribing ever did", mode_reviewed: "2026-09-07", tag: "subscribers" }
    graphql: [] # no GraphQL API exists for this provider (REST-only)
