<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: motchalini</title>
    <description>The latest articles on DEV Community by motchalini (@motchalini).</description>
    <link>https://dev.to/motchalini</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4017204%2F35162e32-1b86-4c10-acdc-5c894b277f6c.png</url>
      <title>DEV Community: motchalini</title>
      <link>https://dev.to/motchalini</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/motchalini"/>
    <language>en</language>
    <item>
      <title>Your AI makes CI green by cheating. I built three GitHub Actions to stop it.</title>
      <dc:creator>motchalini</dc:creator>
      <pubDate>Mon, 06 Jul 2026 07:22:19 +0000</pubDate>
      <link>https://dev.to/motchalini/your-ai-makes-ci-green-by-cheating-i-built-three-github-actions-to-stop-it-4pal</link>
      <guid>https://dev.to/motchalini/your-ai-makes-ci-green-by-cheating-i-built-three-github-actions-to-stop-it-4pal</guid>
      <description>&lt;p&gt;All your checks are green. Before you merge, one question worth asking: &lt;strong&gt;is it green because the code was fixed, or because the checker was silenced?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There are two ways to turn a red CI run green. You can fix the problem, or you can make the tool stop reporting it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Type error? &lt;code&gt;as any&lt;/code&gt; or &lt;code&gt;# type: ignore&lt;/code&gt; makes it vanish.&lt;/li&gt;
&lt;li&gt;Failing test? &lt;code&gt;it.skip&lt;/code&gt; or &lt;code&gt;@pytest.mark.skip&lt;/code&gt; takes it out of the run. Or &lt;code&gt;it.only&lt;/code&gt; quietly skips everything &lt;em&gt;else&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Linter warning? &lt;code&gt;eslint-disable&lt;/code&gt; or &lt;code&gt;# noqa&lt;/code&gt; and it's quiet.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// tsc stays green&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;compute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;# type: ignore   — mypy stays green
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Silencing is almost always faster than fixing, and AI coding agents (Claude Code, Copilot, Cursor) are very good at fast. To be clear, this isn't a claim that AI is malicious: anything optimizing for "make CI green" — an agent, or a human at 6pm before a release — will sometimes take the shortcut. The problem is that human review is bad at catching it. One &lt;code&gt;as any&lt;/code&gt; in a 400-line diff slips through.&lt;/p&gt;

&lt;p&gt;So I stopped relying on reviewer willpower and built a mechanical stop: three small GitHub Actions I call the &lt;strong&gt;&lt;code&gt;*-ratchet&lt;/code&gt; family&lt;/strong&gt;. Their design stance is the opposite of AI code-review SaaS: &lt;strong&gt;no AI, no SaaS, no config&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The ratchet idea
&lt;/h2&gt;

&lt;p&gt;A ratchet is the mechanism that lets a wrench turn one way and never back. All three actions share one loop:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set a &lt;strong&gt;baseline&lt;/strong&gt;: the number of escape hatches you have &lt;em&gt;today&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;If a PR &lt;strong&gt;increases&lt;/strong&gt; the count → the gate fails.&lt;/li&gt;
&lt;li&gt;If it &lt;strong&gt;decreases&lt;/strong&gt; → the gate prints &lt;code&gt;IMPROVED&lt;/code&gt;, and you lower the baseline to lock it in.&lt;/li&gt;
&lt;li&gt;The number can only go down.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important part: &lt;strong&gt;you don't start from zero.&lt;/strong&gt; Real codebases have &lt;code&gt;Any&lt;/code&gt;s and &lt;code&gt;# noqa&lt;/code&gt;s that exist for defensible reasons. "Keep today's mess, forbid tomorrow's" is an on-ramp a team will actually take — and every cleanup tightens the ratchet by one click.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three gates
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. type-ratchet — stops type-checker silencing
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Counts:&lt;/strong&gt; TypeScript &lt;code&gt;any&lt;/code&gt; (in type position), &lt;code&gt;as any&lt;/code&gt;, &lt;code&gt;@ts-ignore&lt;/code&gt;, &lt;code&gt;@ts-expect-error&lt;/code&gt;; Python &lt;code&gt;Any&lt;/code&gt;, &lt;code&gt;# type: ignore&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why existing tools don't cover it:&lt;/strong&gt; &lt;code&gt;tsc&lt;/code&gt; and &lt;code&gt;mypy --strict&lt;/code&gt; don't count their own escape hatches — that's what the hatches are for. Write &lt;code&gt;as any&lt;/code&gt; and the type checker goes green without telling anyone it was silenced.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .github/workflows/type-ratchet.yml&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Type Ratchet Gate&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;gate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;motchalini-llc/type-ratchet@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;typescript&lt;/span&gt;   &lt;span class="c1"&gt;# python | typescript | auto&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Notes:&lt;/strong&gt; test files (&lt;code&gt;*.test.ts&lt;/code&gt;, &lt;code&gt;*.spec.ts&lt;/code&gt;) are excluded from the count — mocks legitimately use &lt;code&gt;as any&lt;/code&gt; — but you can still pass a &lt;code&gt;typecheck-command&lt;/code&gt; (e.g. &lt;code&gt;pnpm exec tsc --noEmit&lt;/code&gt;) to type-check everything alongside the count. Baselines are split (&lt;code&gt;baseline-any&lt;/code&gt; / &lt;code&gt;baseline-suppress&lt;/code&gt;) so you can tighten dynamic types and type-suppressions independently.&lt;/p&gt;

&lt;p&gt;One honest caveat: detection is grep-based, so an "any" inside a comment or string can false-positive. That's the price of transparency (you can read exactly what's counted); an opt-in ESLint &lt;code&gt;no-explicit-any&lt;/code&gt; backing is on the roadmap for people who want strictness.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. test-ratchet — stops test dodging
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Counts two different sins:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Skipped tests&lt;/strong&gt; (ratcheted via &lt;code&gt;baseline-skip&lt;/code&gt;): Python &lt;code&gt;@pytest.mark.skip/skipif/xfail&lt;/code&gt;, &lt;code&gt;pytest.skip()&lt;/code&gt;, unittest &lt;code&gt;@skip&lt;/code&gt; variants; TypeScript &lt;code&gt;.skip&lt;/code&gt; / &lt;code&gt;.todo&lt;/code&gt; / &lt;code&gt;.fails&lt;/code&gt; on &lt;code&gt;it/test/describe/bench&lt;/code&gt;, plus &lt;code&gt;xit&lt;/code&gt; / &lt;code&gt;xdescribe&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;.only&lt;/code&gt;&lt;/strong&gt; (hard-forbidden at zero, TypeScript): a single &lt;code&gt;it.only&lt;/code&gt; makes the runner execute &lt;em&gt;that block and nothing else&lt;/em&gt; — the rest of your suite silently stops running while CI stays green. This one isn't baselined; one occurrence is red (disable with &lt;code&gt;forbid-only: false&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why existing tools don't cover it:&lt;/strong&gt; &lt;code&gt;eslint-plugin-no-only-tests&lt;/code&gt; is the known answer for &lt;code&gt;.only&lt;/code&gt;, but it assumes TypeScript &lt;em&gt;and&lt;/em&gt; an ESLint setup. I couldn't find a cross-language, zero-config PR gate — and nothing at all that ratchets pytest skips.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .github/workflows/test-ratchet.yml&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Test Ratchet Gate&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;gate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;motchalini-llc/test-ratchet@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;typescript&lt;/span&gt;   &lt;span class="c1"&gt;# python | typescript | auto&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. suppress-ratchet — stops linter silencing
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Counts:&lt;/strong&gt; TypeScript &lt;code&gt;eslint-disable&lt;/code&gt; (line / next-line / block) and &lt;code&gt;biome-ignore&lt;/code&gt;; Python &lt;code&gt;# noqa&lt;/code&gt;, &lt;code&gt;# ruff: noqa&lt;/code&gt;, &lt;code&gt;# pylint: disable&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why existing tools don't cover it:&lt;/strong&gt; linters are &lt;em&gt;designed&lt;/em&gt; to respect suppression comments. The more you write, the quieter the linter gets, and nothing in the standard toolchain pushes back on the trend.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .github/workflows/suppress-ratchet.yml&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Suppress Ratchet Gate&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;gate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;motchalini-llc/suppress-ratchet@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;typescript&lt;/span&gt;      &lt;span class="c1"&gt;# python | typescript | auto&lt;/span&gt;
          &lt;span class="na"&gt;baseline-suppress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;12'&lt;/span&gt;   &lt;span class="c1"&gt;# suppressions already in the codebase&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Notes:&lt;/strong&gt; type suppressions (&lt;code&gt;@ts-ignore&lt;/code&gt;, &lt;code&gt;# type: ignore&lt;/code&gt;) are deliberately &lt;em&gt;not&lt;/em&gt; counted here — they belong to type-ratchet, and the same comment shouldn't be double-counted by two gates. Vendor and generated trees (&lt;code&gt;node_modules&lt;/code&gt;, &lt;code&gt;dist&lt;/code&gt;, &lt;code&gt;.venv&lt;/code&gt;, &lt;code&gt;.next&lt;/code&gt;, …) are excluded.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design decisions shared by all three
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero-dependency bash.&lt;/strong&gt; Each action is a composite action plus one &lt;code&gt;gate.sh&lt;/code&gt;; the machinery is essentially &lt;code&gt;grep&lt;/code&gt; and &lt;code&gt;wc&lt;/code&gt;. You can read the script and know exactly what's counted — the opposite of a black-box AI reviewer. Your code never leaves your CI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero config.&lt;/strong&gt; One &lt;code&gt;uses:&lt;/code&gt; line. Language is auto-detected from &lt;code&gt;pyproject.toml&lt;/code&gt; / &lt;code&gt;tsconfig.json&lt;/code&gt; and friends.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One-way only.&lt;/strong&gt; Increase fails, decrease tightens. Baseline lives in an input or a &lt;code&gt;baseline-file&lt;/code&gt; in the repo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The gates test themselves.&lt;/strong&gt; Each repo ships clean/dirty fixtures and a self-test workflow asserting &lt;em&gt;clean passes, dirty fails&lt;/em&gt; (test- and suppress-ratchet run that matrix for both languages), so the gate can't silently break.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Light version first, heavy version on demand.&lt;/strong&gt; v1 is a free grep gate. Autofix (&lt;code&gt;mode: fix&lt;/code&gt;) and AST-precise detection are on the roadmap, opt-in, with your own LLM API key and a hard cost cap — I'll build them when someone actually asks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Global count, honestly.&lt;/strong&gt; The judgment is a repo-wide total; per-file baselines (monorepos) are future work. Coarse, but it's what makes zero-config possible.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Dogfooding numbers
&lt;/h2&gt;

&lt;p&gt;Before publishing I ran all three on my own two repos. Real numbers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;crypto-trading-system&lt;/strong&gt; (Python, &lt;code&gt;mypy --strict&lt;/code&gt;): baseline &lt;code&gt;any=5&lt;/code&gt;, type-suppressions &lt;code&gt;2&lt;/code&gt;, skips &lt;code&gt;0&lt;/code&gt;, linter suppressions &lt;strong&gt;&lt;code&gt;4&lt;/code&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;meguri&lt;/strong&gt; (Next.js 15 / React 19, strict TS): &lt;code&gt;any=0&lt;/code&gt; at adoption — so there the same gate runs as &lt;em&gt;keep-it-at-zero insurance&lt;/em&gt; rather than a cleanup driver.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;baseline-suppress: 4&lt;/code&gt; was the instructive one. Those four were pre-existing &lt;code&gt;# noqa&lt;/code&gt;s in test code — &lt;code&gt;F401&lt;/code&gt; unused imports, &lt;code&gt;PLC0415&lt;/code&gt; function-level imports — each left there on purpose. If the gate had demanded zero on day one, I'd have ripped it out by lunch. "Today's 4 are fine; the 5th is not" is what made it adoptable, and that exact number now sits in the README example.&lt;/p&gt;

&lt;p&gt;I also opened a demo PR that deliberately added &lt;code&gt;any&lt;/code&gt; / &lt;code&gt;as any&lt;/code&gt; to watch the gate go red with inline annotations on the offending lines, then closed it. (Deliberate demo — not a caught-the-AI-in-the-act story.)&lt;/p&gt;

&lt;h2&gt;
  
  
  How they were built
&lt;/h2&gt;

&lt;p&gt;The bash is honestly simple. The hard part was deciding &lt;strong&gt;what counts and what doesn't&lt;/strong&gt;: excluding test files from the &lt;code&gt;any&lt;/code&gt; count, keeping type suppressions out of suppress-ratchet, hard-forbidding &lt;code&gt;.only&lt;/code&gt; instead of baselining it. Those line-drawing decisions are the product.&lt;/p&gt;

&lt;p&gt;Mechanically: solo dev plus Claude Code, two to three days per action, the same playbook three times — build → dogfood on my own repos → publish to the GitHub Marketplace → announce. The skeleton (composite action + &lt;code&gt;gate.sh&lt;/code&gt; + clean/dirty self-test + README + roadmap) carries over; only the patterns change. Hence: three siblings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;p&gt;All MIT-licensed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Type Ratchet: &lt;a href="https://github.com/marketplace/actions/type-ratchet" rel="noopener noreferrer"&gt;https://github.com/marketplace/actions/type-ratchet&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Test Ratchet: &lt;a href="https://github.com/marketplace/actions/test-ratchet" rel="noopener noreferrer"&gt;https://github.com/marketplace/actions/test-ratchet&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Suppress Ratchet: &lt;a href="https://github.com/marketplace/actions/suppress-ratchet" rel="noopener noreferrer"&gt;https://github.com/marketplace/actions/suppress-ratchet&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub org: &lt;a href="https://github.com/motchalini-llc" rel="noopener noreferrer"&gt;https://github.com/motchalini-llc&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;X: &lt;a href="https://x.com/motchalini" rel="noopener noreferrer"&gt;https://x.com/motchalini&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you try one and something's missing, an issue is the strongest possible vote for what gets built next.&lt;/p&gt;

</description>
      <category>github</category>
      <category>ci</category>
      <category>typescript</category>
      <category>python</category>
    </item>
  </channel>
</rss>
