Measuring API drift: 1,291 fields GitLab sends that this library does not model
Everyone can contribute. Help move this issue forward while earning points, leveling up and collecting rewards.
Why now
#2269 (closed) asked how to notice when this library falls behind the API it wraps, and the answer there was that there is no great way to detect it, with the OpenAPI schema not comprehensive enough to serve as the oracle. That issue is closed, which is why this is a new one rather than a comment on it.
I have been building an MCP server on top of this library (https://github.com/jmrplens/gitlab-mcp-server) and needed that answer for my own reasons, so I built the measurement. This issue is the result: the method, what it currently finds, what it cannot see, and an offer.
I can confirm the OpenAPI observation independently. I started there, and the schema gives no response body for 553 of 1847 operations, so a comparison against it silently passes over the endpoints it does not describe.
The method
Boot a released gitlab-ee image and ask the loaded Rails application what its own REST API is, through one gitlab-rails runner script. What comes back is every Grape entity with the fields it exposes, the entity each field renders with, and the condition gating it, read from inside the image; every mounted route with the entity its desc annotates; and the licensed-feature table evaluated. It needs no licence and no fixtures, because a licence gates feature_available? when a request is served, not when a class is defined.
Then pair each struct in this library with the endpoints its own service methods route to, parsed from the route() templates and withMethod options in the source, and diff what the endpoint sends against what the struct carries.
Why the application rather than a scan of the same Ruby: a scan cannot see a name that is not written down. GeoSiteStatus exposes around 600 fields by iterating a constant assembled from two method calls, so the source says only "expose the loop variable". Measured against a scan of the same release with inheritance resolved, 551 of 582 entities agree and the 31 that do not hold 1,935 fields the scan never saw.
What it finds today
Measured against GitLab 19.3.1-ee: 897 distinct fields that an endpoint sends and the struct decoding it does not carry. Every one of them is a field this library does not model, not a field my own code fails to publish.
That number has been through two corrections I would rather state than have someone find. The raw run reports 1,424, of which 61 are answered by my own declaration table, mostly routes whose desc annotates an entity the endpoint does not actually render. The remaining 1,363 are reported once per entity that renders the field, so a field carried by four user entities appears four times. A third correction came later and is the largest: 997 of the 1,001 Geo findings name one entity, API::Entities::GeoSiteStatus, and 394 of them are the same field names counted a second time against a second output type, so Geo is 607 distinct pairs rather than 1,001. Counted as distinct fields the total is 897.
The headline is still misleading on its own, so here is the shape of it immediately:
- 607 of them are one entity,
API::Entities::GeoSiteStatus, and they are a matrix rather than a list. See the collapsible block below before reading anything into that number: it is not 607 things to write down. - The remaining 290 spread across 27 structs, and that is the part a person can act on. 188 of the 290 are sent with no condition on them at all.
- None of the 290 is modelled by this library today. The same pass that finds them checks each against the struct's own json tags, so a field my server publishes from its own captured response and one this library lacks are told apart rather than conflated.
- The record separates the fields sent unconditionally from those behind a condition and carries the condition text for each, so the two never have to be guessed at.
The 27 structs a person can act on
One row per struct, with the entities its endpoints render. "Always" counts the fields the entity exposes with no condition on them at all, so every response of every endpoint that renders it carries them.
These are distinct fields. My raw run counts 362 for the same set, because it reports a field once per entity that renders it: User is 16 fields seen through ServiceAccount, UserProfile, UserPublic and UserWithAdmin, which is 64 rows of one report and 16 things to add. Where a pairing was ambiguous between BasicMergeRequest and MergeRequest I have counted it once, under MergeRequest.
| Struct | Fields | Always | Rendered by |
|---|---|---|---|
ProjectGroup |
49 | 35 | Group |
Group |
31 | 14 | BasicProjectDetails, Group, and 1 more |
IssueRelation |
25 | 19 | RelatedIssue |
MemberRole |
25 | 25 | MemberRole |
MergeRequest |
22 | 20 | ApprovalState, MergeRequestBasic, and 1 more |
Project |
17 | 4 | Project |
User |
16 | 8 | ServiceAccount, UserProfile, and 2 more |
AccessRequest |
15 | 8 | AccessRequester, Member |
BillableGroupMember |
13 | 7 | Member |
PipelineInfo |
12 | 12 | Ci::Pipeline |
Issue |
11 | 9 | EpicIssue, MRNote |
Namespace |
8 | 0 | Namespace |
Hook |
7 | 5 | Hook |
BasicMergeRequest |
6 | 4 | MergeRequestBasic |
Package |
5 | 2 | Package |
ProjectDeployKey |
4 | 2 | DeployKeysProject |
ProjectUser |
4 | 3 | UserBasic |
Snippet |
4 | 2 | ProjectSnippet |
ContributionEvent |
3 | 2 | Event |
ProjectEvent |
3 | 2 | Event |
GroupHook |
2 | 1 | GroupHook |
GroupMember |
2 | 1 | Member |
InstanceDeployKey |
2 | 2 | DeployKey |
MergeRequestDependency |
1 | 0 | MergeRequestDependency |
ProjectApprovalRule |
1 | 0 | ProjectApprovalRule |
ProjectHook |
1 | 0 | ProjectHook |
SSHKey |
1 | 1 | SSHKey |
The field lists, one collapsible block each.
ProjectGroup, 49 fields
Rendered by API::Entities::Group.
| Field | Sent |
|---|---|
allow_personal_snippets |
under a condition |
archived |
always |
auto_devops_enabled |
always |
auto_duo_code_review_enabled |
under a condition |
built_in_project_templates_enabled |
under a condition |
created_at |
always |
crm_enabled |
always |
custom_attributes |
always |
default_branch |
always |
default_branch_protection |
always |
default_branch_protection_defaults |
always |
description |
always |
duo_core_features_enabled |
under a condition |
duo_features_enabled |
under a condition |
duo_namespace_access_rules |
under a condition |
emails_disabled |
always |
emails_enabled |
always |
file_template_project_id |
under a condition |
ldap_access |
always |
ldap_cn |
always |
ldap_group_links |
under a condition |
lfs_enabled |
always |
lock_built_in_project_templates_enabled |
under a condition |
lock_duo_features_enabled |
under a condition |
lock_math_rendering_limits_enabled |
always |
lock_resource_access_token_notify_inherited |
always |
marked_for_deletion_on |
always |
math_rendering_limits_enabled |
always |
max_artifacts_size |
always |
mentions_disabled |
always |
organization_id |
always |
parent_id |
always |
path |
always |
project_creation_level |
always |
repository_storage |
under a condition |
request_access_enabled |
always |
require_two_factor_authentication |
always |
resource_access_token_notify_inherited |
always |
root_storage_statistics |
under a condition |
saml_group_links |
under a condition |
share_with_group_lock |
always |
shared_runners_setting |
always |
show_diff_preview_in_email |
always |
statistics |
always |
subgroup_creation_level |
always |
two_factor_grace_period |
always |
visibility |
always |
web_based_commit_signing_enabled |
under a condition |
wiki_access_level |
always |
Group, 31 fields
Rendered by API::Entities::BasicProjectDetails, API::Entities::Group, API::Entities::GroupDetail.
| Field | Sent |
|---|---|
ai_settings |
under a condition |
allow_personal_snippets |
under a condition |
auto_ban_user_on_excessive_projects_download |
under a condition |
auto_duo_code_review_enabled |
under a condition |
built_in_project_templates_enabled |
under a condition |
duo_core_features_enabled |
under a condition |
duo_namespace_access_rules |
under a condition |
forks_count |
under a condition |
http_url_to_repo |
always |
last_activity_at |
always |
license |
always |
license_url |
always |
lock_built_in_project_templates_enabled |
under a condition |
lock_resource_access_token_notify_inherited |
always |
name_with_namespace |
always |
namespace |
always |
path_with_namespace |
always |
readme_url |
under a condition |
resource_access_token_notify_inherited |
always |
service_access_tokens_expiration_enforced |
under a condition |
show_diff_preview_in_email |
always |
ssh_url_to_repo |
always |
star_count |
always |
step_up_auth_required_oauth_provider |
under a condition |
tag_list |
always |
topics |
always |
unique_project_download_limit |
under a condition |
unique_project_download_limit_alertlist |
under a condition |
unique_project_download_limit_allowlist |
under a condition |
unique_project_download_limit_interval_in_seconds |
under a condition |
web_based_commit_signing_enabled |
under a condition |
IssueRelation, 25 fields
Rendered by API::Entities::RelatedIssue.
| Field | Sent |
|---|---|
_links |
always |
blocking_issues_count |
always |
closed_at |
always |
closed_by |
always |
discussion_locked |
always |
downvotes |
always |
epic |
under a condition |
epic_iid |
under a condition |
has_tasks |
always |
health_status |
under a condition |
imported |
always |
imported_from |
always |
issue_type |
always |
iteration |
under a condition |
merge_requests_count |
always |
moved_to_id |
always |
service_desk_reply_to |
always |
severity |
always |
start_date |
always |
subscribed |
under a condition |
task_completion_status |
always |
task_status |
under a condition |
time_stats |
always |
type |
always |
upvotes |
always |
MemberRole, 25 fields
Rendered by API::Entities::MemberRole.
| Field | Sent |
|---|---|
admin_ai_catalog_item |
always |
admin_ai_catalog_item_consumer |
always |
admin_integrations |
always |
admin_protected_branch |
always |
admin_protected_environments |
always |
admin_runners |
always |
admin_security_attributes |
always |
apply_security_scan_profiles |
always |
create_security_scan_profiles |
always |
delete_security_scan_profiles |
always |
destroy_package |
always |
read_admin_cicd |
always |
read_admin_groups |
always |
read_admin_monitoring |
always |
read_admin_projects |
always |
read_admin_subscription |
always |
read_admin_users |
always |
read_agent_artifacts |
always |
read_compliance_dashboard |
always |
read_crm_contact |
always |
read_security_attribute |
always |
read_security_scan_profiles |
always |
read_virtual_registry |
always |
update_sec_ai_workflow_settings |
always |
update_security_scan_profiles |
always |
MergeRequest, 22 fields
Rendered by API::Entities::ApprovalState, API::Entities::MergeRequestBasic, API::Entities::MergeRequestChanges.
| Field | Sent |
|---|---|
approval_rules_left |
always |
approvals_before_merge |
always |
approvals_left |
always |
approvals_required |
always |
approved |
always |
approved_by |
always |
approver_groups |
always |
approvers |
always |
changes |
always |
description_html |
under a condition |
has_approval_rules |
always |
invalid_approvers_rules |
always |
merge_request_approvers_available |
always |
merge_status |
always |
multiple_approval_rules_available |
always |
overflow |
always |
reference |
always |
require_password_to_approve |
always |
suggested_approvers |
always |
title_html |
under a condition |
user_can_approve |
always |
user_has_approved |
always |
Project, 17 fields
Rendered by API::Entities::Project.
| Field | Sent |
|---|---|
description_html |
always |
duo_dependency_bump_breaking_changes_enabled |
under a condition |
duo_foundational_flows_enabled |
under a condition |
duo_remote_flows_enabled |
under a condition |
duo_sast_fp_detection_enabled |
under a condition |
duo_sast_vr_workflow_enabled |
under a condition |
duo_secret_detection_fp_enabled |
under a condition |
max_pipelines_per_merge_train |
under a condition |
merge_train_enforcement |
under a condition |
only_allow_merge_if_all_status_checks_passed |
under a condition |
repository_object_format |
always |
secret_push_protection_enabled |
under a condition |
security_policy_pipeline_must_succeed |
under a condition |
show_diff_preview_in_email |
always |
spp_repository_pipeline_access |
under a condition |
warn_about_potentially_unwanted_characters |
always |
web_based_commit_signing_enabled |
under a condition |
User, 16 fields
Rendered by API::Entities::ServiceAccount, API::Entities::UserProfile, API::Entities::UserPublic, API::Entities::UserWithAdmin.
| Field | Sent |
|---|---|
avatar_path |
under a condition |
bio_html |
always |
commit_email |
always |
discord |
always |
enterprise_group_associated_at |
under a condition |
enterprise_group_id |
under a condition |
followers |
under a condition |
following |
under a condition |
github |
always |
is_followed |
under a condition |
local_time |
always |
preferred_language |
always |
pronouns |
always |
provisioned_by_group_id |
under a condition |
unconfirmed_email |
under a condition |
work_information |
always |
AccessRequest, 15 fields
Rendered by API::Entities::AccessRequester, API::Entities::Member.
| Field | Sent |
|---|---|
avatar_path |
under a condition |
avatar_url |
always |
created_by |
under a condition |
custom_attributes |
always |
email |
under a condition |
expires_at |
always |
group_saml_identity |
under a condition |
group_scim_identity |
under a condition |
is_using_seat |
under a condition |
locked |
always |
member_role |
always |
membership_state |
always |
override |
under a condition |
public_email |
always |
web_url |
always |
BillableGroupMember, 13 fields
Rendered by API::Entities::Member.
| Field | Sent |
|---|---|
access_level |
always |
avatar_path |
under a condition |
created_by |
under a condition |
custom_attributes |
always |
expires_at |
always |
group_saml_identity |
under a condition |
group_scim_identity |
under a condition |
is_using_seat |
under a condition |
locked |
always |
member_role |
always |
membership_state |
always |
override |
under a condition |
public_email |
always |
PipelineInfo, 12 fields
Rendered by API::Entities::Ci::Pipeline.
| Field | Sent |
|---|---|
archived |
always |
before_sha |
always |
committed_at |
always |
coverage |
always |
detailed_status |
always |
duration |
always |
finished_at |
always |
queued_duration |
always |
started_at |
always |
tag |
always |
user |
always |
yaml_errors |
always |
Issue, 11 fields
Rendered by API::Entities::EpicIssue, API::Entities::MRNote.
| Field | Sent |
|---|---|
blocking_issues_count |
always |
epic_iid |
under a condition |
has_tasks |
always |
imported |
always |
imported_from |
always |
note |
always |
relative_position |
always |
severity |
always |
start_date |
always |
task_status |
under a condition |
type |
always |
Namespace, 8 fields
Rendered by API::Entities::Namespace.
| Field | Sent |
|---|---|
additional_purchased_storage_ends_on |
under a condition |
additional_purchased_storage_size |
under a condition |
end_date |
under a condition |
extra_shared_runners_minutes_limit |
under a condition |
max_seats_used_changed_at |
under a condition |
projects_count |
under a condition |
root_repository_size |
under a condition |
shared_runners_minutes_limit |
under a condition |
Hook, 7 fields
Rendered by API::Entities::Hook.
| Field | Sent |
|---|---|
alert_status |
always |
branch_filter_strategy |
always |
custom_headers |
under a condition |
custom_webhook_template |
always |
disabled_until |
always |
organization_id |
under a condition |
push_events_branch_filter |
always |
BasicMergeRequest, 6 fields
Rendered by API::Entities::MergeRequestBasic.
| Field | Sent |
|---|---|
approvals_before_merge |
always |
description_html |
under a condition |
merge_status |
always |
reference |
always |
title_html |
under a condition |
work_in_progress |
always |
Package, 5 fields
Rendered by API::Entities::Package.
| Field | Sent |
|---|---|
conan_package_name |
under a condition |
creator_id |
always |
project_id |
under a condition |
project_path |
under a condition |
versions |
always |
ProjectDeployKey, 4 fields
Rendered by API::Entities::DeployKeysProject.
| Field | Sent |
|---|---|
last_used_at |
always |
projects_with_readonly_access |
under a condition |
projects_with_write_access |
under a condition |
usage_type |
always |
ProjectUser, 4 fields
Rendered by API::Entities::UserBasic.
| Field | Sent |
|---|---|
avatar_path |
under a condition |
custom_attributes |
always |
locked |
always |
public_email |
always |
Snippet, 4 fields
Rendered by API::Entities::ProjectSnippet.
| Field | Sent |
|---|---|
http_url_to_repo |
under a condition |
imported |
always |
imported_from |
always |
ssh_url_to_repo |
under a condition |
ContributionEvent, 3 fields
Rendered by API::Entities::Event.
| Field | Sent |
|---|---|
imported |
always |
imported_from |
always |
wiki_page |
under a condition |
ProjectEvent, 3 fields
Rendered by API::Entities::Event.
| Field | Sent |
|---|---|
imported |
always |
imported_from |
always |
wiki_page |
under a condition |
GroupHook, 2 fields
Rendered by API::Entities::GroupHook.
| Field | Sent |
|---|---|
organization_id |
under a condition |
repository_update_events |
always |
GroupMember, 2 fields
Rendered by API::Entities::Member.
| Field | Sent |
|---|---|
avatar_path |
under a condition |
custom_attributes |
always |
InstanceDeployKey, 2 fields
Rendered by API::Entities::DeployKey.
| Field | Sent |
|---|---|
last_used_at |
always |
usage_type |
always |
MergeRequestDependency, 1 fields
Rendered by API::Entities::MergeRequestDependency.
| Field | Sent |
|---|---|
blocked_merge_request |
under a condition |
ProjectApprovalRule, 1 fields
Rendered by API::Entities::ProjectApprovalRule.
| Field | Sent |
|---|---|
coverage_minimum_threshold |
under a condition |
ProjectHook, 1 fields
Rendered by API::Entities::ProjectHook.
| Field | Sent |
|---|---|
organization_id |
under a condition |
SSHKey, 1 fields
Rendered by API::Entities::SSHKey.
| Field | Sent |
|---|---|
last_used_at |
always |
Geo, and why its number is not what it looks like
I first reported this as 1,001 fields across two structs, generated per replicable resource. Having looked properly, that was wrong twice over, and both errors are worth stating because they are the two failure modes this whole report is exposed to.
It is one entity, not two. 997 of the 1,001 findings name API::Entities::GeoSiteStatus. They arrive against two different Go types, and the 394 reported against the second are a strict subset of the 603 reported against the first, so counting both double-counts. API::Entities::GeoSite accounts for exactly four findings: blob_download_timeout, checksum_mismatch_report_threshold, checksum_mismatch_self_heal_cooldown_minutes and selective_sync_organization_ids. That entity has 23 fields in total and none of them is generated.
And the remaining 603 are a matrix. API::Entities::GeoSiteStatus exposes 93 distinct replicable prefixes, each carrying up to twelve of the same metrics: count, registry_count, synced_count, failed_count, checksummed_count, checksum_failed_count, checksum_total_count, verified_count, verification_failed_count, synced_in_percentage, verified_in_percentage and replication_enabled. 535 of the field names decompose that way exactly, and most of the rest are one more metric per resource, oldest_unsynced_time.
So the honest description is not "600 generated fields nobody can enumerate". It is one object of about 93 replicables times about 12 metrics, flattened into a single namespace by Grape.
That matters for what anyone would do about it. Written as named struct fields it is 600 lines that need regenerating every time GitLab adds a replicable, and a new replicable would silently read as fresh drift on the next release. Read as a map keyed by replicable, with the metrics as a small struct, it is one shape that absorbs new replicables on its own. I am not asking for either here; I am withdrawing the suggestion that this part is unenumerable, because it is not.
What it cannot see
Stating these before anyone else has to find them.
- REST only. The GraphQL surface is a separate walk with its own results and is not in these numbers.
- A route whose
descnames the wrong entity inflates the count. The pairing trusts that annotation, and where it is wrong the comparison is wrong with it. I carry a declaration table for the cases I have found and would rather be told about others. - A field GitLab offers is a candidate, not a defect. GitLab adds fields weekly. Nothing here says this library is broken; it says the two have drifted, which is a different and much less alarming claim.
- The record is a pin. It describes one released image, so it ages, and re-measuring is one command rather than a re-derivation.
What this is not asking for
Not a bulk addition. I read the answer in issue 2269 that these are easy to edit when somebody needs them, and I think that policy is the right one for a library this size: a field nobody consumes is a field nobody notices is wrong.
So this is a measurement offered as a menu, not a backlog. I am sending merge requests only for the fields I actually consume, one struct at a time, each with the entity and line that proves it.
What I have sent so far
Each of these references this issue, and each carries the GitLab source for the field it adds.
| Merge request | Struct | Field | State |
|---|---|---|---|
| !3040 (merged) | Appearance, ChangeAppearanceOptions |
site_name |
merged, released in v3.2.0 |
| !3041 | Topic |
organization_id |
open |
| !3042 (merged) | BroadcastMessage |
color |
merged, released in v3.1.0 |
| !3043 (merged) | Agent (cluster agents) |
is_receptive |
merged, released in v3.3.0 |
| !3044 | LicenseTemplate |
popular |
open |
| !3045 (merged) | SecureFile |
file_extension |
merged, released in v3.3.0 |
| !3046 (merged) | GroupSCIMIdentity |
extern_uid (wrong json tag, not a missing field) |
merged, released in v3.2.0 |
| !3047 (merged) | GroupServiceAccount |
public_email, unconfirmed_email |
merged, released in v3.4.0 |
| !3048 | Hook (system hooks), AddHookOptions, EditHookOptions |
organization_id, alert_status, disabled_until, push_events_branch_filter, branch_filter_strategy, custom_webhook_template, custom_headers |
open |
| !3049 (merged) | InstanceDeployKey, ProjectDeployKey |
last_used_at, usage_type |
open |
| !3050 | ContributionEvent, ProjectEvent |
imported, imported_from, wiki_page |
open |
| !3051 | Namespace |
root_repository_size, projects_count, shared_runners_minutes_limit, extra_shared_runners_minutes_limit, additional_purchased_storage_size, additional_purchased_storage_ends_on, max_seats_used_changed_at, end_date |
open |
| !3052 | Package, plus the new PackageVersion and GetProjectPackage |
conan_package_name, creator_id, versions |
open |
| !3053 (merged) | Snippet |
imported, imported_from, ssh_url_to_repo, http_url_to_repo |
open |
Two of these are worth a word beyond the table.
!3046 (merged) is the one finding of a different kind: the field is modelled, under a json tag GitLab does not send, so it decodes as empty and no amount of reading the struct reveals it. A comparison against what the endpoint actually sends is the only thing that finds that class.
!3047 (merged) came from a review comment on my own repository claiming GroupServiceAccount already carried unconfirmed_email. It does not; ServiceAccount does. Checking rather than accepting the claim turned one field into a small map of the same entity modelled three times and unevenly:
| Struct | id |
username |
name |
email |
unconfirmed_email |
public_email |
|---|---|---|---|---|---|---|
ServiceAccount (users.go) |
yes | yes | yes | yes | yes | no |
ProjectServiceAccount |
yes | yes | yes | yes | yes | no |
GroupServiceAccount |
yes | yes | yes | yes | no | no |
All three decode API::Entities::ServiceAccount. Five of its six fields are unconditional, so every response of every service account endpoint carries them. unconfirmed_email is the exception: it is exposed under if: ->(service_account) { service_account.unconfirmed_email.present? } and so appears only while a confirmation is pending. public_email is therefore missing from all three structs and is sent every time, and unconfirmed_email is missing from the group one.
!3047 (merged) adds both to GroupServiceAccount. I have not sent the public_email additions for the other two, and will if this shape of contribution is wanted.
The six from !3048 on are a second batch and are shaped differently, which is worth saying rather than leaving to be discovered. The first eight were one unconditional field per struct, chosen because they were the least arguable cases. These are whole structs: thirty-two fields across six of them, and most are conditional, so each merge request says who receives each field rather than only where it is exposed. Two of them turned up something a field list alone would not have. !3052 needed GetProjectPackage as well, because versions is exposed unless: opts[:collection] and the only endpoint that sends it had no wrapper, so adding the field alone would have added a field nothing could populate. And !3049 is as interesting for what it leaves alone: projects_with_write_access and projects_with_readonly_access are gated on options that only GET /deploy_keys passes, so InstanceDeployKey is right to carry them and ProjectDeployKey is right not to.
What went to GitLab's own documentation
Checking each field against doc/api/ before sending it turned up a second kind of gap, and I am recording it here because it is the same measurement finding it and because it bears on how much a documentation-derived oracle can be trusted.
Of the eight fields in the first tranche, two were documented nowhere on their page, and a third page carried public_email in none of its fourteen example responses. So for those fields the drift is not only between GitLab and this library; it is also between GitLab and its own reference documentation, which is where a caller would go to find out whether the field exists at all.
| Merge request | Page | What it adds |
|---|---|---|
| gitlab-org/gitlab!254507 (merged) | doc/api/secure_files.md |
file_extension in all four example responses |
| gitlab-org/gitlab!254511 | doc/api/cluster_agents.md |
is_receptive in the three response attribute tables and the four example responses |
| gitlab-org/gitlab!254519 (merged) | doc/api/service_accounts.md |
public_email in all fourteen service account example responses, and email in the two that predate it |
| gitlab-org/gitlab!254538 | doc/api/system_hooks.md |
the seven entity fields missing from all three example responses, and custom_webhook_template in the two request parameter tables |
| gitlab-org/gitlab!254540 | doc/api/deploy_keys.md |
last_used_at and usage_type in all nine example responses, and three fingerprint_sha256 keys that had been left as an empty string |
| gitlab-org/gitlab!254542 | doc/api/events.md |
wiki_page, through a wiki page event added to one example, since none of the nine events shown was one |
| gitlab-org/gitlab!254543 | doc/api/namespaces.md |
the four compute minute and purchased storage attributes, in the block where the page already shows its permission-gated ones |
| gitlab-org/gitlab!254547 | doc/api/packages.md |
conan_package_name, and a correction to the versions example, which showed a pipelines array where the entity exposes a single pipeline and omitted tags |
| gitlab-org/gitlab!254552 | doc/api/snippets.md, doc/api/project_snippets.md |
ssh_url_to_repo and http_url_to_repo in the response attribute tables and examples that lacked them, and imported and imported_from in the public snippets section |
The question
Two, and either answer is useful:
- Would a regenerated drift record, or a check that runs it, be welcome in this repository? I am happy to contribute the generator rather than keep it on my side, and equally happy to leave it where it is if on-demand editing is the policy you want to keep.
- If it stays on my side, is there interest in me posting the full list so other contributors can pick from it? It is a good source of small, well-evidenced first contributions, which is why I am offering it rather than quietly working through it alone.