Skip to content
Insights · Engineering

Which ruleset did that push hit?

Name the ruleset that push hit: the id, the name, and the enforcement. A different ruleset can name another ref, and another repository does not list it.

Scroll
EngineeringOct 30, 202613 min readBy Salman Naqvi, Founder & CEO
Which ruleset did that push hit?

A client says the push was blocked, or says anyone can still push. Tonight, three proofs, in a repository the agency or the client can open. Name the ruleset that push hit: the ruleset id, the name, and the enforcement. Show a different ruleset whose id, or whose name, is not this one. Show another client's repository that does not list this ruleset. If any of the three needs a laptop the agency takes home, you have not shown the ruleset. You have a screenshot and a guess.

This is the ruleset. It is not the release. Which release did that tag name? is a release id, a tag, and a draft flag. A tag can exist while no ruleset names that ref, and a ruleset name is not a tag. It is not the workflow. Which workflow did that run execute? is a run id and a file path. A workflow file is not a ruleset id. It is not the review. Which review blocked that merge? is a review state. A required review inside a ruleset is a rule type. It is not the review object on one pull request. It is not the dependency alert. Which alert did that dependency raise? is an alert number. An alert number is not an actor id.

None of what follows is a pass rate for this repository, and none of it is legal advice. The fields below are one host's current description of a repository ruleset. The percentages below that are a 2025 study of npm repositories and the Scorecard scores those repositories received. An enforcement enum is not a census of your clients. A classifier that never opened this repository cannot name the ruleset the push hit tonight. They do tell you which numbers people mix up when they try to sound precise about a rule they have not opened.

GitHub's create example sends name super cool ruleset, target branch, and enforcement active. The name is 18 characters. branch is the default target. The request may set target to branch, tag, or push. Three names. The response schema's target enum adds repository. Four names. A target you were allowed to send is not the same list as a target the response is allowed to store. Do not add repository to a request because the response schema printed it, and do not drop it from a response because the request page did not. enforcement is disabled, active, or evaluate. Three names. The example is active. evaluate is not active. The page says evaluate lets admins test rules before enforcing them, and that evaluate is only available with GitHub Enterprise. An evaluate ruleset on a plan that cannot store evaluate is not an active ruleset you forgot to read. The example's one rule has type commit_author_email_pattern, operator contains, and pattern github. github is 6 characters. One rule is not every rule the schema allows (GitHub, REST API endpoints for rules).

The response schema requires an integer id, and the example does not print one. actor_id 234 is on the bypass actor. 234 is not a ruleset id. actor_type on that actor is Team. bypass_mode is always, which is also the default. The actor types are Integration, OrganizationAdmin, RepositoryRole, Team, DeployKey, and User. Six names. bypass_mode is always, pull_request, or exempt. Three names. current_user_can_bypass, a different field, is always, pull_requests_only, never, or exempt. Four names. pull_request is not pull_requests_only. Three is not four. OrganizationAdmin ignores actor_id. DeployKey requires actor_id to be null. A null actor id is not 234. The example includes refs/heads/main and refs/heads/master, and excludes refs/heads/dev*. Those strings are 15, 17, and 15 characters. 17 is not 15. main is not master. The exclude pattern ends in a star. The include patterns do not. A star on one line is not a star you paste onto the others. Create returns 201. Get returns 200. Validation failure returns 422. 201 is not 200, and 422 is not a ruleset id. The version header the page names is 2026-03-10. That date is not a tag, and it is not 234.

The rule types on the create response are a closed list, and the example uses one of them. creation, update, deletion, required_linear_history, merge_queue, required_deployments, required_signatures, pull_request, required_status_checks, non_fast_forward, commit_message_pattern, commit_author_email_pattern, committer_email_pattern, branch_name_pattern, tag_name_pattern, workflows, code_scanning, code_quality, code_coverage, copilot_code_review, license_compliance_scanning, file_path_restriction, max_file_path_length, file_extension_restriction, and max_file_size. Twenty-five names. The example's type is the twelfth if you count from creation, and it is one name either way. One is not twenty-five. commit_author_email_pattern is not committer_email_pattern. The author and the committer are different rules. branch_name_pattern is not tag_name_pattern. A push that matched a tag ruleset is not a push that matched a branch ruleset, even when both rulesets are named super cool ruleset in two different examples you have not opened.

The integers inside those rules are limits, and they are not the actor id. merge_queue's check_response_timeout_minutes runs from 1 to 360. max_entries_to_build, max_entries_to_merge, and min_entries_to_merge each run from 0 to 100. min_entries_to_merge_wait_minutes runs from 0 to 360. 360 minutes is not 360 entries. 100 is not 234. required_approving_review_count runs from 0 to 10. 10 is not 100. max_file_path_length runs from 1 to 32767. 32767 is not 18, the length of the example name. max_file_size runs from 1 to 100, and the unit on that parameter is megabytes. 100 megabytes is not 100 entries, and it is not a ruleset id. code coverage's minimum and maximum drop are floats from 0 to 100. A float is not the integer 234. grouping_strategy is ALLGREEN or HEADGREEN. Two names. ALLGREEN is not HEADGREEN. source_type on the response is Repository, Organization, or Enterprise. Three names. The example does not print a source. An absent source is not Repository.

The study people reach for when they want a protection rate did not open this repository. Nusrat Zahan and Laurie Williams, at North Carolina State University, measured OpenSSF Scorecard on npm GitHub repositories. The initial dataset is 146,951 repositories with Scorecard scores, out of 172,999. 172,999 minus 146,951 is 26,048. The page says the remainder did not generate a score. 26,048 is that subtraction. It is not a ruleset id, and it is not 234. They also extracted Scorecard from BigQuery for 761,602 repositories before the inclusion rules. 761,602 is not 172,999. A manual check covered 100 repositories. 100 is not 26,048. The paper is the npm security-outcomes study, and the preprint is arXiv:2504.14026 (Zahan and Williams, Prioritizing Security Practice Adoption).

The missing-time sentence and the table do not use one count. The abstract says 85% lacked a mean time to remediate, and that the authors extracted a 22K subset from the 146K dataset. The body prints 22,083 packages with that time. Table 2 prints the MTTR count as 22,543. 22,543 minus 22,083 is 460. 460 is not zero, so the body and the table are not the same subset. 146,951 minus 22,083 is 124,868, which is 84.97% of 146,951. That rounds to 85% at the nearest percent. 146,951 minus 22,543 is 124,408, which is 84.66%. 84.66% rounds to 84.7%, not 85%. 0.85 times 146,951 is 124,908.35, which is not an integer, and 146,951 minus that product is not 22,083 and not 22,543. Do not cite 85% as if both counts produced it. 22K is not 22,083, and 22,083 is not 22,543.

Table 1 and Table 4 do not describe Branch Protection with one triple. Table 1's columns are a score of -1 and a score from 0 to 10. Branch-Protection is <1% with a parenthetical 7, and 99.9%. 7 divided by 146,951 is 0.00476%, which rounds to the 0.005% Table 4 prints in the -1 column. The parenthetical 7 matches that rounding. <1% is a looser phrase than 0.005%. Table 4 then splits the rest into 85.9% at score 0 and 14% at scores 1 through 10. 85.9 plus 14 is 99.9, which matches Table 1's 99.9% in the broad column. 0.005 plus 85.9 plus 14 is 99.905, not 100. The page does not print the missing tenth of a percent. Do not invent it. 14% of someone else's npm set is not enforcement active on this repository.

The other rows are not one arithmetic either. Code-Review in Table 1 is <1.4% with a parenthetical 2,071, and 98.6%. 2,071 divided by 146,951 is 1.409%. 1.409% is not less than 1.4%. The inequality and the count disagree. Table 4 prints Code Review as 1.4%, 74.6%, and 24%. 1.4 plus 74.6 plus 24 is 100. 74.6 plus 24 is 98.6, which matches Table 1's broad column. Pinned-Dependencies in Table 1 is 72.2% and 27.8%. 72.2 plus 27.8 is 100. Table 4 prints 72.2%, 0, and 27.9%. 72.2 plus 27.9 is 100.1, not 100. 27.8 is not 27.9. Maintained in Table 1 is 0 and 100%. Table 4 prints 0.001%, 86.7%, and 13.3%. 0.001 plus 86.7 plus 13.3 is 100.001, not 100, and 0.001% is not 0. Token-Permissions in Table 1 is 74.4% and 26.8%. 74.4 plus 26.8 is 101.2, not 100. Packaging is 97.4% and 2.5%. 97.4 plus 2.5 is 99.9, not 100. Dangerous-Workflow is 73.2% and 26.8%, and that pair does sum to 100. A row that sums is not a row that sums to 101.2.

The model table is a third set of numbers, and it is not a ruleset. The abstract says the regression used 12 Scorecard metrics. The methods say they studied 13 out of 18, after removing five: CI-Tests, Contributors, Dependency-Update-Tool, Signed Releases, and Packaging. 18 minus 5 is 13. 13 is not 12. Table 1 lists the 18. A later sentence says a manual analysis used 50 repositories per metric. 50 is not the 100 repositories they checked when a score would not generate. Do not merge the two samples. For vulnerability count, the zero-inflated model coefficient is -1.4 and the weighted average treatment effect is -1.9. -1.4 is not -1.9. For time to remediate, the coefficient is -0.1 and the treatment effect is 74.7. A negative coefficient and a positive effect are not the same direction. -0.1 is not 74.7. For time to update, the coefficient is -0.2 and the effect is -0.5. -0.2 is not -0.5. The correlation they print between the two time metrics is 0.7. Vulnerability count correlates with them at -0.32 and -0.04. 0.7 is not -0.32. The variance inflation factor they flag on downloads is 15. 15 is not 0.7. The top score bin is 7.3 to 9.1. 9.1 is not 10, and the text says no project achieved a perfect score. A bin is not enforcement active. None of these figures is the integer id the create example never printed.

Do the three proofs on one real ruleset, in the repository that actually holds it. First, the binding. Copy the ruleset id, the name, the target, and the enforcement. If the example you were shown has no id, that example is not your ruleset. If enforcement is evaluate, write evaluate. Do not rewrite it as active because the words sit in one enum. If the rules array has one type, write that type. Do not expand it to twenty-five because the schema lists twenty-five. If actor_id is 234 on a sample, that sample is not your team. Second, the other ruleset. A different ruleset, with a different id or a different name, is not this one. A table of Branch Protection percentages is not that second ruleset. If you cannot show a ruleset that is not this one, you have a counter, not a record. Third, the other repository. A list that belongs to another client does not contain this ruleset id. If the only list mixes every client's branches, write that. A tenant you cannot name is the finding.

Three moves feel like the proof and are a second problem. Turning enforcement to active because disabled looked careless, before you have copied the id. Changing enforcement does not tell you which ruleset the push hit. Quoting 14% because it looks precise, while the push in front of you is one ref, and the repositories that produced that percent had not opened this client's tree. Asking a model which of the twenty-five rule types it was. The model will pick a plausible name. It will not open the ruleset. A release you have not kept, while the client is asking which tag is live, is which release did that tag name?. Opening that screen does not name the ruleset id.

The path is ordinary when an operator can open one client's project without opening the next client's project as the way to prove it. Gigbase is a multi-user agency portal: projects, teams, and clients in one workspace. The shape that matters here is one client's project you can point at, distinct from the next client's project. That case is not a ruleset ledger. Nothing in the description is a headcount, a duration, or a result figure. If the only control on the screen shows every client at once and will not name a ruleset, you do not have this proof. You have a directory.

There is a version of this afternoon where the agency should not take the work. The work is not sold under the agency's name. The client asked to meet the builders. The room only has a slide. The buyer only wants a template. Or the buyer wants a legal opinion about what a ruleset promises. A white label software development partner is the page for capacity sold under the agency's name. It does not rank anyone, including us. 14% is not this repository, and 234 is not this repository.

When the repository is real and the ruleset is not on a screen you can open, the missing object is specific. The id, the name, and the enforcement, a different ruleset that is not that one, and another client's repository that does not list it. A white-label engagement that expects this will put the repository in the client's organization, or in yours, before the first push, because a rule that lives only in a vendor dashboard is not an id you can hand the client. One that can only paste active into chat is telling you who holds the ruleset. Where the next slice is one capability and the acceptance sentence names the ruleset id, an AI integration sprint is the shape that can require the three proofs as the definition of done. Where you are not sure which repository the current engagement protects, a two-week AI readiness assessment maps the systems. The findings are yours. They are not a promise that 14% of this tree has a ruleset, and they are not 234.

The payout a charge settled into, and the container that code used, are different objects: which payout did that charge settle? and which container did that code use?. Do not record either on this page. A payout id is not a ruleset id. A memory limit is not an enforcement value. The branch a pull targeted is a different object: which branch did that pull target?. Do not record it here. A base ref is not a ruleset id.

Before you tell the client which rule blocked the push, write the three lines. The ruleset id, the name, and the enforcement, or the field the response did not store. A different ruleset that is not that one. Another repository that does not hold it. Do not flip evaluate to active to avoid the word, and do not ask a model which of the twenty-five types it was. A paper can tell you how often other npm repositories scored above zero on branch protection. The binding is the ruleset you can defend.

Questions

Three records, in a repository the agency or the client can open. The ruleset id, the name, and the enforcement. A different ruleset whose id or name is not this one. Another client's repository that does not list this ruleset. If the example has no id, write that the example did not store one.

No. A percentage of Scorecard rows in someone else's npm set is not the id on this ruleset. A ruleset you can defend is the id, the name, and the enforcement, or a written line that the response did not store an id. 14% in one table is not enforcement active, and 234 on a sample actor is not a ruleset id.

When the work is not sold under the agency's name, when the client asked to meet the builders, when the room only has a slide, when the buyer only wants a template, or when the buyer wants a legal opinion.

Find this useful? Tell Google to show you more of it.

Let's put AI to work in your business.

A 30-minute call. You bring the workflow or the roadmap — we'll tell you what's feasible, what it costs, and what we'd build first.

Book a call→