getreadystack commited on
Commit
e07d0fc
·
verified ·
1 Parent(s): cfc7950

Upload index.html with huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +280 -17
index.html CHANGED
@@ -1,19 +1,282 @@
1
  <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  </html>
 
1
  <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <title>Coverage Gate Lint — find coverage gates that cannot fail — free online check</title>
7
+ <style>
8
+ :root{color-scheme:light}body{margin:0;font:15px/1.55 system-ui,-apple-system,"Segoe UI",sans-serif;background:#faf9f5;color:#1a1512}
9
+ .wrap{max-width:960px;margin:0 auto;padding:28px 18px 60px}h1{font-size:26px;margin:0 0 6px}.lede{color:#4a403a;margin:0 0 16px}
10
+ textarea{width:100%;min-height:260px;font:13px/1.45 ui-monospace,Menlo,Consolas,monospace;padding:12px;border:1px solid #d9d0c4;border-radius:8px;box-sizing:border-box}
11
+ .bar{display:flex;gap:10px;align-items:center;margin:12px 0}button{font:600 15px system-ui;padding:10px 18px;border:0;border-radius:8px;background:#1a1512;color:#fff;cursor:pointer}
12
+ input[type=date]{font:14px system-ui;padding:8px;border:1px solid #d9d0c4;border-radius:6px}
13
+ table{border-collapse:collapse;width:100%;font-size:14px;margin-top:10px}th,td{text-align:left;padding:8px 10px;border-bottom:1px solid #eee;vertical-align:top}th{font-size:12px;letter-spacing:.06em;text-transform:uppercase;color:#7a6e65}
14
+ .sev.error{color:#a8551f;font-weight:700}.sev.warn,.sev.warning{color:#96691f}.ok{color:#2a6446;font-weight:600}.sum{font-weight:600}
15
+ .note{font-size:13px;color:#7a6e65;margin-top:18px}#paid{margin-top:22px;padding:14px 16px;border:1px solid #e2d8cb;border-radius:10px;background:#fffdfa}
16
+ </style>
17
+ <script data-grow-initializer="">!(function(){window.growMe||((window.growMe=function(e){window.growMe._.push(e);}),(window.growMe._=[]));var e=document.createElement("script");(e.type="text/javascript"),(e.src="https://faves.grow.me/main.js"),(e.defer=!0),e.setAttribute("data-grow-faves-site-id","U2l0ZTphZjljMzgyMC0yMmU5LTRhYjgtYTIxNS03OTRhMGY1N2ExYzM=");var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t);})();</script>
18
+ <!--yj-canon-s101--><link rel="canonical" href="https://getreadystack.com/tools/coverage-gate-lint"></head>
19
+ <body>
20
+ <div class="wrap">
21
+ <h1>Coverage Gate Lint — find coverage gates that cannot fail</h1>
22
+ <p class="lede">Lints codecov.yml, .coveragerc, jest/vitest config and CI steps for coverage gates that report a number but can never fail the build. Runs entirely in your browser — nothing is uploaded.</p>
23
+ <textarea id="src" spellcheck="false"># codecov.yml — generated for us, reviewed by nobody
24
+ codecov:
25
+ require_ci_to_pass: false
26
+
27
+ coverage:
28
+ precision: 2
29
+ range: "70...100"
30
+ status:
31
+ project:
32
+ default:
33
+ target: auto
34
+ threshold: 10%
35
+ informational: true
36
+ if_ci_failed: success
37
+ if_not_found: success
38
+ patch: off
39
+
40
+ ignore:
41
+ - "**"
42
+
43
+ jest:
44
+ coverageThreshold: {}
45
+ thresholds:
46
+ statements: 0
47
+ branches: 0
48
+
49
+ [tool.coverage.report]
50
+ precision = 2
51
+ show_missing = true
52
+
53
+ steps:
54
+ - name: Tests with coverage
55
+ continue-on-error: true
56
+ run: pytest --cov=app --cov-report=xml || true
57
+ - name: Upload coverage
58
+ uses: codecov/codecov-action@v5
59
+ with:
60
+ fail_ci_if_error: false</textarea>
61
+ <div class="bar"><button id="go">Check</button><label>as of <input type="date" id="today"></label></div>
62
+ <div id="out" aria-live="polite"></div>
63
+ <p id="upgrade" style="margin:14px 0 0"><a href="https://buy.polar.sh/polar_cl_aNRhjxJUQvfo4XkkVInz22Vk3dZYMt8tpZyj14a3Wmz" data-polar-checkout data-polar-checkout-theme="light">Full version: sweep every coverage config and CI workflow in the workspace and export a dated evidence report</a><br><small>$29 once · one licence key per person or CI seat · 7-day full refund. A contract CI engineer bills about $150/hour to audit those files by hand.</small></p>
64
+ <div id="paid"><strong>Free here:</strong> Check the coverage config file you have open and name every gate in it that can never fail the build. <strong>In the editor:</strong> Scan every coverage config and CI workflow in the workspace at once and export a dated evidence report of which gates block and which do not — that part asks for a licence key.</div>
65
+ <p class="note">Same engine as the VS Code extension, byte for byte.</p>
66
+ </div>
67
+ <script>var CGL_RULES = [
68
+ {
69
+ "check": "codecov_informational",
70
+ "kind": "line",
71
+ "sev": "error",
72
+ "re": "informational:\\s*true",
73
+ "msg": "informational: true — this Codecov status reports a number and can never fail the build.",
74
+ "fix": "informational: false"
75
+ },
76
+ {
77
+ "check": "codecov_if_ci_failed_success",
78
+ "kind": "line",
79
+ "sev": "error",
80
+ "re": "if_ci_failed:\\s*success",
81
+ "msg": "if_ci_failed: success — the coverage check passes even when the test job itself failed.",
82
+ "fix": "if_ci_failed: error"
83
+ },
84
+ {
85
+ "check": "codecov_patch_off",
86
+ "kind": "line",
87
+ "sev": "error",
88
+ "re": "^\\s*patch:\\s*(off|false|null)\\s*$",
89
+ "msg": "patch: off — coverage of newly changed lines is never gated, so new untested code merges freely.",
90
+ "fix": "patch:\\n default:\\n target: 80%"
91
+ },
92
+ {
93
+ "check": "codecov_if_not_found_success",
94
+ "kind": "line",
95
+ "sev": "warn",
96
+ "re": "if_not_found:\\s*success",
97
+ "msg": "if_not_found: success — a missing coverage report is reported as a pass.",
98
+ "fix": "if_not_found: failure"
99
+ },
100
+ {
101
+ "check": "codecov_threshold_wide",
102
+ "kind": "line",
103
+ "sev": "warn",
104
+ "re": "threshold:\\s*(([5-9])|([1-9][0-9]+))(\\.[0-9]+)?%",
105
+ "msg": "threshold is 5% or wider — coverage can fall this far every merge and the gate still passes.",
106
+ "fix": "threshold: 1%"
107
+ },
108
+ {
109
+ "check": "codecov_fail_ci_false",
110
+ "kind": "line",
111
+ "sev": "warn",
112
+ "re": "fail_ci_if_error:\\s*false",
113
+ "msg": "fail_ci_if_error: false — an upload that never arrives is silently treated as a green build.",
114
+ "fix": "fail_ci_if_error: true"
115
+ },
116
+ {
117
+ "check": "coveragerc_fail_under_zero",
118
+ "kind": "line",
119
+ "sev": "error",
120
+ "re": "(\"?fail_under\"?\\s*[=:]\\s*0(\\.0+)?\\b)",
121
+ "msg": "fail_under = 0 — coverage.py exits 0 at any coverage, including none at all.",
122
+ "fix": "fail_under = 80"
123
+ },
124
+ {
125
+ "check": "coverage_omit_broad",
126
+ "kind": "line",
127
+ "sev": "warn",
128
+ "re": "^\\s*(-\\s*|(omit|ignore)\\s*[=:]\\s*)[\\\"']?(\\*{1,2}(/\\*)?)[\\\"']?\\s*$",
129
+ "msg": "a whole-tree omit/ignore pattern removes the files from the denominator, so the percentage measures nothing.",
130
+ "fix": "list the specific paths to omit"
131
+ },
132
+ {
133
+ "check": "jest_threshold_empty",
134
+ "kind": "line",
135
+ "sev": "error",
136
+ "re": "coverageThreshold\\s*:\\s*\\{\\s*\\}",
137
+ "msg": "coverageThreshold is an empty object — Jest/Vitest accepts it and enforces nothing.",
138
+ "fix": "coverageThreshold: { global: { lines: 80 } }"
139
+ },
140
+ {
141
+ "check": "jest_threshold_zero",
142
+ "kind": "line",
143
+ "sev": "error",
144
+ "re": "^\\s*\"?(statements|branches|lines|functions)\"?\\s*:\\s*0(\\.0+)?\\s*,?\\s*$",
145
+ "msg": "a coverage threshold of 0 looks configured but passes at zero percent.",
146
+ "fix": "set the threshold to the number you actually hold"
147
+ },
148
+ {
149
+ "check": "ci_continue_on_error",
150
+ "kind": "line",
151
+ "sev": "error",
152
+ "re": "continue-on-error:\\s*true",
153
+ "msg": "continue-on-error: true — this step is allowed to fail, so the coverage gate under it cannot stop a merge.",
154
+ "fix": "remove continue-on-error from the coverage step"
155
+ },
156
+ {
157
+ "check": "ci_swallow_exit",
158
+ "kind": "line",
159
+ "sev": "error",
160
+ "re": "(coverage|pytest|jest|vitest|nyc|go test|npm (run )?test)[^\\n]*(\\|\\|\\s*(true|exit\\s*0)|;\\s*exit\\s*0)",
161
+ "msg": "the exit code of the coverage command is discarded with || true, so a failing gate reports success.",
162
+ "fix": "let the command's exit code reach the runner"
163
+ },
164
+ {
165
+ "check": "coveragerc_no_fail_under",
166
+ "kind": "absent",
167
+ "sev": "error",
168
+ "when": "\\[(tool\\.coverage\\.report|report)\\]",
169
+ "missing": "fail_under",
170
+ "msg": "a coverage report section with no fail_under: the run prints a percentage and always exits 0.",
171
+ "fix": "add fail_under under the report section"
172
+ },
173
+ {
174
+ "check": "codecov_no_status",
175
+ "kind": "absent",
176
+ "sev": "error",
177
+ "when": "^\\s*coverage:\\s*$",
178
+ "missing": "^\\s*status:",
179
+ "msg": "a coverage: block with no status: block — Codecov posts a comment but never sets a check a branch rule can require.",
180
+ "fix": "add a status: block with project and patch targets"
181
+ }
182
+ ];</script>
183
+ <script>// Coverage Gate Lint — one brain, used by the extension and by the free web page.
184
+ const RULES = (typeof module !== 'undefined') ? require('./rules.json') : window.CGL_RULES;
185
+
186
+ // A coverage config is only interesting if it talks about coverage at all.
187
+ const SCOPE = /(coverage|codecov|fail_under|coverageThreshold|pytest-cov|nyc|jacoco|lcov|cobertura)/i;
188
+
189
+ function lines(text) { return String(text == null ? '' : text).split(/\r\n|\r|\n/); }
190
+
191
+ function lineOf(text, index) {
192
+ return text.slice(0, index).split(/\r\n|\r|\n/).length;
193
+ }
194
+
195
+ function check(text, opts) {
196
+ opts = opts || {};
197
+ const src = String(text == null ? '' : text);
198
+ const findings = [];
199
+ if (!src.trim()) return { findings: findings, scanned: 0, rule_count: RULES.length };
200
+
201
+ const rows = lines(src);
202
+ const inScope = SCOPE.test(src);
203
+
204
+ for (let i = 0; i < RULES.length; i++) {
205
+ const rule = RULES[i];
206
+
207
+ if (rule.kind === 'line') {
208
+ const re = new RegExp(rule.re, 'i');
209
+ for (let n = 0; n < rows.length; n++) {
210
+ const row = rows[n];
211
+ if (/^\s*(#|\/\/)/.test(row)) continue; // a commented-out gate is not a live gate
212
+ if (!re.test(row)) continue;
213
+ findings.push({ check: rule.check, sev: rule.sev, msg: rule.msg, line: n + 1, fix: rule.fix, text: row.trim() });
214
+ }
215
+ continue;
216
+ }
217
+
218
+ if (rule.kind === 'absent') {
219
+ if (!inScope) continue;
220
+ const when = new RegExp(rule.when, 'mi');
221
+ const hit = when.exec(src);
222
+ if (!hit) continue;
223
+ if (new RegExp(rule.missing, 'mi').test(src)) continue;
224
+ findings.push({
225
+ check: rule.check, sev: rule.sev, msg: rule.msg,
226
+ line: lineOf(src, hit.index), fix: rule.fix, text: String(hit[0]).trim()
227
+ });
228
+ }
229
+ }
230
+
231
+ findings.sort(function (a, b) { return a.line - b.line; });
232
+ return { findings: findings, scanned: rows.length, rule_count: RULES.length, today: opts.today || '' };
233
+ }
234
+
235
+ const _API = { engine: { check: check }, RULES: RULES, RULE_COUNT: RULES.length };
236
+ if (typeof module !== 'undefined') { module.exports = _API; }
237
+ if (typeof window !== 'undefined') { window.CGLENGINE = _API; }
238
+ </script>
239
+ <script>// ⛔뼈대 — kit/scaffold.py 가 찍는다 (s143). findings [{check,sev,msg,line?}] → 글/HTML. 같은 파일이 Node 와 브라우저에서 산다.
240
+ 'use strict';
241
+ function escapeHtml(s) { return String(s == null ? '' : s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;'); }
242
+ function summaryLine(res) {
243
+ const f = (res && res.findings) || []; const e = f.filter(function (x) { return String(x.sev || 'error').toLowerCase().startsWith('err'); }).length;
244
+ return f.length ? (f.length + ' finding' + (f.length === 1 ? '' : 's') + ' (' + e + ' error' + (e === 1 ? '' : 's') + ')') : 'Clean — no findings.';
245
+ }
246
+ function toText(res, label) {
247
+ const f = (res && res.findings) || [];
248
+ const lines = ['== ' + (label || '') + ' — ' + summaryLine(res)];
249
+ f.forEach(function (x) { lines.push(' ' + String(x.sev || 'error').toUpperCase().slice(0, 4) + ' ' + (x.line ? 'L' + x.line + ' ' : '') + (x.check || x.id || '') + ' ' + (x.msg || x.message || '')); });
250
+ return lines.join('\n');
251
+ }
252
+ function toHtml(res) {
253
+ const f = (res && res.findings) || [];
254
+ if (!f.length) return '<p class="ok">' + escapeHtml(summaryLine(res)) + '</p>';
255
+ const rows = f.map(function (x) { return '<tr><td class="sev ' + escapeHtml(String(x.sev || 'error')) + '">' + escapeHtml(String(x.sev || 'error')) + '</td><td>' + (x.line ? 'L' + escapeHtml(x.line) : '') + '</td><td><code>' + escapeHtml(x.check || x.id || '') + '</code></td><td>' + escapeHtml(x.msg || x.message || '') + '</td></tr>'; }).join('');
256
+ return '<p class="sum">' + escapeHtml(summaryLine(res)) + '</p><table><thead><tr><th>Level</th><th>Line</th><th>Check</th><th>What</th></tr></thead><tbody>' + rows + '</tbody></table>';
257
+ }
258
+ var CGLREPORT = { escapeHtml: escapeHtml, summaryLine: summaryLine, toText: toText, toHtml: toHtml };
259
+ if (typeof module !== 'undefined' && module.exports) module.exports = CGLREPORT;
260
+ else window.CGLREPORT = CGLREPORT;
261
+ </script>
262
+ <script>
263
+ (function(){
264
+ var src=document.getElementById('src'), out=document.getElementById('out'), go=document.getElementById('go'), today=document.getElementById('today');
265
+ today.value=new Date().toISOString().slice(0,10);
266
+ function run(){ try { var res=window.CGLENGINE.engine.check(src.value,{today:today.value}); out.innerHTML=window.CGLREPORT.toHtml(res); } catch(e){ out.innerHTML='<p class="sev error">Could not run: '+String(e.message||e)+'</p>'; } }
267
+ go.onclick=run; if (src.value.trim()) run();
268
+ })();
269
+ </script>
270
+ <script defer data-auto-init src="https://cdn.jsdelivr.net/npm/@polar-sh/checkout@latest/dist/embed.global.js"></script>
271
+
272
+
273
+ <section data-yj-install="free" style="margin:2rem auto 1rem;max-width:46rem;padding:1.25rem 1.25rem;border:1px solid #cfe3d6;border-radius:12px;background:#f6fbf8;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .4rem;font-size:1.2rem">Install free</h2><p style="margin:0 0 .8rem;color:#41505f">Free for the file open in your editor - no key, no limit. The workspace sweep and the report ask for a key.</p><a href="https://marketplace.visualstudio.com/items?itemName=ReadyStack.coverage-gate-lint" rel="noopener" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">VS Code Marketplace</a><a href="https://open-vsx.org/extension/readystack/coverage-gate-lint" rel="noopener" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">Open VSX (Cursor, VSCodium)</a><a href="https://www.npmjs.com/package/@readystack/coverage-gate-lint" rel="noopener" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">npm</a><a href="https://hub.docker.com/r/getreadystack/coverage-gate-lint" rel="noopener" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">Docker Hub</a><pre style="margin:.5rem 0 0;padding:.6rem .8rem;background:#f3f5f8;border-radius:8px;font-size:.9rem;overflow:auto">ext install ReadyStack.coverage-gate-lint
274
+ npx @readystack/coverage-gate-lint &lt;file&gt;
275
+ docker run --rm -v &quot;$PWD:/w&quot; getreadystack/coverage-gate-lint /w</pre><p style="margin:.6rem 0 0;font-size:.92rem;color:#41505f"><a href="https://buy.polar.sh/polar_cl_l6iN1uWt0FwWu7tBsczD0jWpP2vxFM54Wdwqb3KPi1G" rel="nofollow" style="color:#0f7b3f;text-decoration:underline">Team? One key for every ReadyStack linter, 5 seats, $149 once</a></p></section>
276
+ <section data-yj-alert="rule" style="margin:1rem auto 1.5rem;max-width:46rem;padding:1.1rem 1.25rem;border:1px solid #d9dee6;border-radius:12px;background:#fbfcfd;font:15px/1.55 system-ui,-apple-system,Segoe UI,sans-serif"><b style="font-size:1.05rem">Get one email when this rule changes</b><div style="opacity:.78;margin:.35rem 0 .8rem">We watch the regulation and vendor sources behind Coverage Gate Lint every day. When a rule changes, you get a single email with what changed and the updated check. No newsletter.</div><div style="display:flex;gap:8px;flex-wrap:wrap"><input id="yjae" type="email" placeholder="you@example.com" style="flex:1;min-width:210px;padding:11px 13px;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:#fff;color:inherit"><button id="yjab" style="padding:11px 18px;border-radius:8px;border:0;cursor:pointer;background:#0f7b3f;color:#fff;font:600 15px system-ui,sans-serif">Notify me</button></div><div id="yjao" hidden style="margin-top:.6rem;color:#0f7b3f">You're on the list. One email when it changes.</div><script>(function(){var b=document.getElementById("yjab"),e=document.getElementById("yjae");if(!b||!e)return;b.addEventListener("click",function(){var v=e.value.trim();if(!/.+@.+\..+/.test(v))return;try{localStorage.setItem("yj_em","1");}catch(_){}fetch(location.origin+"/api/subscribe",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:v,slug:"coverage-gate-lint",lang:"en",source:"rule_alert"})}).then(function(r){var o=document.getElementById("yjao");o.hidden=false;if(!r.ok){o.textContent="Could not save - please try again.";}}).catch(function(){var o=document.getElementById("yjao");o.hidden=false;o.textContent="Could not save - please try again.";});});})();</script></section>
277
+
278
+ <section data-yj-cta="paid" style="margin:3rem auto;max-width:46rem;padding:1.5rem 1.25rem;border:1px solid #d8dee9;border-radius:12px;background:#fbfcfe;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .5rem;font-size:1.25rem">Get the complete version <span class="yj-price">$29</span></h2><p style="margin:.25rem 0 1rem;color:#41505f">This page is the working piece. The full pack has everything below.</p><p style="margin:0 0 1rem;color:#41505f">Finds the coverage gates in your repo that can never fail a build</p><p style="margin:0 0 1rem;color:#5b6b7c;font-size:.94rem">A contract CI/DevOps engineer bills about $150/hour, and judging every coverage config and workflow in a mid-sized monorepo by hand is most of an afternoon</p><a href="https://buy.polar.sh/polar_cl_aNRhjxJUQvfo4XkkVInz22Vk3dZYMt8tpZyj14a3Wmz" rel="nofollow" style="display:inline-block;padding:.7rem 1.3rem;border-radius:8px;background:#1b64f2;color:#fff;text-decoration:none;font-weight:600">Buy the full version — $29</a></section>
279
+ <section data-yj="yj-facts-v1" style="max-width:920px;margin:48px auto 0;padding:0 20px;font-family:system-ui,sans-serif"><style>.yj-article p{font:400 15.5px/1.7 system-ui,sans-serif;color:#26313b;margin:0 0 12px;max-width:72ch}.yj-article h2,.yj-article h3,.yj-article h4{font:600 17px/1.35 system-ui,sans-serif;color:#1b1f24;margin:22px 0 8px}.yj-article table{border-collapse:collapse;margin:10px 0 16px;font:14px/1.45 system-ui,sans-serif}.yj-article th,.yj-article td{border:1px solid #e2e6ea;padding:6px 10px;text-align:left}.yj-article th{background:#f4f6f8}.yj-article pre{background:#0f1720;color:#e6edf3;padding:12px 14px;border-radius:8px;overflow:auto;font:13px/1.5 ui-monospace,Menlo,monospace}.yj-article code{font:13px ui-monospace,Menlo,monospace;background:#f1f3f5;padding:1px 4px;border-radius:3px}.yj-article pre code{background:none;padding:0}.yj-article ul,.yj-article ol{font:15px/1.6 system-ui,sans-serif;color:#26313b}</style><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:34px 0 6px;color:#1b1f24">Questions people ask</h2><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What does Coverage Gate Lint actually do?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">It reads a coverage configuration file — codecov.yml, .coveragerc, setup.cfg, pyproject.toml, a Jest or Vitest config, or a CI workflow — and reports every line that makes the coverage gate incapable of failing a build. Fourteen rules cover informational statuses, missing fail_under, empty thresholds, whole-tree omits and discarded exit codes.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Who is it for?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Platform and CI engineers who own a monorepo&#x27;s test pipeline, and the teams preparing EU Cyber Resilience Act or NIS2 evidence this quarter. If someone asks you to show that your coverage gate blocks merges, and your answer depends on a config file you did not write, this is aimed at you.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Why will a normal linter or a chatbot not catch this?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">YAML linters check syntax, and every one of these settings is valid syntax. Codecov and coverage.py accept them without warning, because each is a legitimate option someone deliberately wants. A chatbot can explain one snippet you paste, but it will not tell you which of the config files in your repo are the disarmed ones.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What is free and what is paid?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Free with no licence key: the file you have open is checked against all fourteen rules, with line numbers and the fix for each. Nothing is withheld or watermarked. The paid tier changes scope instead: it sweeps every coverage config and workflow in the workspace and exports a dated report of which gates block.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What would this cost me otherwise?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">A contract CI or DevOps engineer bills about $150 per hour, and opening every coverage config and workflow in a mid-sized monorepo to judge whether each gate can fail is most of an afternoon. The extension is $29 once, one licence key per person or CI seat, with a 7-day full refund.</p></details><script type="application/ld+json" data-yj="yj-faq-ld">{"@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [{"@type": "Question", "name": "What does Coverage Gate Lint actually do?", "acceptedAnswer": {"@type": "Answer", "text": "It reads a coverage configuration file — codecov.yml, .coveragerc, setup.cfg, pyproject.toml, a Jest or Vitest config, or a CI workflow — and reports every line that makes the coverage gate incapable of failing a build. Fourteen rules cover informational statuses, missing fail_under, empty thresholds, whole-tree omits and discarded exit codes."}}, {"@type": "Question", "name": "Who is it for?", "acceptedAnswer": {"@type": "Answer", "text": "Platform and CI engineers who own a monorepo's test pipeline, and the teams preparing EU Cyber Resilience Act or NIS2 evidence this quarter. If someone asks you to show that your coverage gate blocks merges, and your answer depends on a config file you did not write, this is aimed at you."}}, {"@type": "Question", "name": "Why will a normal linter or a chatbot not catch this?", "acceptedAnswer": {"@type": "Answer", "text": "YAML linters check syntax, and every one of these settings is valid syntax. Codecov and coverage.py accept them without warning, because each is a legitimate option someone deliberately wants. A chatbot can explain one snippet you paste, but it will not tell you which of the config files in your repo are the disarmed ones."}}, {"@type": "Question", "name": "What is free and what is paid?", "acceptedAnswer": {"@type": "Answer", "text": "Free with no licence key: the file you have open is checked against all fourteen rules, with line numbers and the fix for each. Nothing is withheld or watermarked. The paid tier changes scope instead: it sweeps every coverage config and workflow in the workspace and exports a dated report of which gates block."}}, {"@type": "Question", "name": "What would this cost me otherwise?", "acceptedAnswer": {"@type": "Answer", "text": "A contract CI or DevOps engineer bills about $150 per hour, and opening every coverage config and workflow in a mid-sized monorepo to judge whether each gate can fail is most of an afternoon. The extension is $29 once, one licence key per person or CI seat, with a 7-day full refund."}}]}</script><div id="yj-ask" style="margin:36px 0 0;padding:18px 18px 16px;border:1px solid #e2e6ea;border-radius:10px;background:#fbfbfc"><h2 style="font:600 19px/1.3 system-ui,sans-serif;margin:0 0 4px;color:#1b1f24">Ask about this tool</h2><p style="font:400 13.5px/1.5 system-ui,sans-serif;margin:0 0 12px;color:#5b6570">One question, answered by the person who built it. Your email only if you want the answer sent.</p><form onsubmit="return yjAsk(event)" style="display:grid;gap:8px"><textarea name="question" required minlength="10" maxlength="2000" rows="3" placeholder="Your question" style="font:14px/1.5 system-ui,sans-serif;padding:10px;border:1px solid #cfd6dd;border-radius:6px"></textarea><div style="display:flex;gap:8px;flex-wrap:wrap"><input type="email" name="email" placeholder="Email (optional)" style="flex:1;min-width:200px;font:14px system-ui,sans-serif;padding:9px 10px;border:1px solid #cfd6dd;border-radius:6px"><button type="submit" style="font:600 14px system-ui,sans-serif;padding:9px 18px;border:0;border-radius:6px;background:#1b1f24;color:#fff;cursor:pointer">Send</button></div><p id="yj-ask-msg" style="font:13px system-ui,sans-serif;margin:2px 0 0;color:#0a6238;min-height:1em"></p></form><script>function yjAsk(e){e.preventDefault();var f=e.target,m=document.getElementById("yj-ask-msg");m.style.color="#0a6238";fetch(location.origin+"/api/ask",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sku:0,slug:"coverage-gate-lint",lang:"en",question:f.question.value,email:f.email.value,page:location.pathname})}).then(function(r){if(!r.ok)throw 0;m.textContent="Thanks \u2014 noted. Answers land on this page and, if you left an email, in your inbox.";f.question.value="";}).catch(function(){m.style.color="#a8551f";m.textContent="Could not send. Please try again in a minute.";});return false;}</script></div></section><section class="yj-related" style="max-width:920px;margin:56px auto 40px;padding:0 20px"><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Same job, next tool</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 20px;color:#5b6570">Free in the browser. The full version is a one-time licence, 7-day refund.</p><div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:14px"><a class="yj-rel-c" href="https://getreadystack.com/tools/dotnet-eol-support-gate"><span class="yj-rel-t">.NET EOL &amp; CRA Support Window Gate</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/qof-90-test-penalty-8996"><span class="yj-rel-t">Form 8996 90% Asset Test and Penalty Checker (2026 testing dates)</span><span class="yj-rel-p">$60</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/cra-24-72-14-reporting-lint"><span class="yj-rel-t">CRA 24/72/14 Reporting Lint (Article 14)</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/cra-readiness-audit"><span class="yj-rel-t">CRA Readiness Audit for EU Cyber Resilience Act</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/csaf-advisory-check-cra-2026"><span class="yj-rel-t">CSAF Advisory Check for CRA 2026</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/firmware-release-gate"><span class="yj-rel-t">Firmware Release Gate for sdkconfig and prj.conf</span><span class="yj-rel-p">$29</span></a></div><style>.yj-rel-c{display:flex;flex-direction:column;gap:8px;padding:15px 16px;border:1px solid #e2e6ea;border-radius:6px;text-decoration:none;background:#fff}.yj-rel-c:hover{border-color:#b9c2cb;background:#fafbfc}.yj-rel-t{font:500 14.5px/1.42 system-ui,sans-serif;color:#1b1f24}.yj-rel-p{font:600 13px system-ui,sans-serif;color:#0a6238}</style></section><!--yj-share-s101--><div style="margin:28px 0 8px;text-align:center"><button id="yjcp" type="button" style="font:inherit;padding:10px 18px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Copy link</button><button id="yjimg" type="button" style="font:inherit;padding:10px 18px;margin-left:8px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Save result as image</button></div><script>(function(){var b=document.getElementById("yjimg");if(!b)return;b.addEventListener("click",function(){var o=document.getElementById("out");var txt=(o&&(o.innerText||o.textContent)||"").trim();if(!txt){b.textContent="(no result yet)";setTimeout(function(){b.textContent="Save result as image";},1500);return;}var lines=txt.split(String.fromCharCode(10)).filter(function(x){return x.trim();}).slice(0,10);var W=1200,P=56,c=document.createElement("canvas");c.width=W;var lh=38,H=P*2+70+lines.length*lh+60;c.height=H;var x=c.getContext("2d");x.fillStyle="#1a1512";x.fillRect(0,0,W,H);x.fillStyle="#f3e9d2";x.font="600 34px system-ui,Segoe UI,Arial";var t=(document.title||"").split("|")[0].trim();x.fillText(t.slice(0,54),P,P+34);x.font="22px ui-monospace,Menlo,Consolas,monospace";x.fillStyle="#e8dcc4";for(var i=0;i<lines.length;i++){x.fillText(lines[i].slice(0,88),P,P+70+i*lh+22);}x.font="600 22px system-ui,Segoe UI,Arial";x.fillStyle="#c9a227";var d=location.hostname.replace("www.","");x.fillText(d,W-P-x.measureText(d).width,H-P+6);c.toBlob(function(bl){var u=URL.createObjectURL(bl),a=document.createElement("a");a.href=u;a.download=(t||"result").replace(/[^a-z0-9]+/gi,"-").toLowerCase()+"-"+d+".png";document.body.appendChild(a);a.click();setTimeout(function(){URL.revokeObjectURL(u);a.remove();},2000);},"image/png");});})();</script><script>(function(){var b=document.getElementById("yjcp");if(!b)return;var t=b.textContent;b.addEventListener("click",function(){var u=location.href.split("#")[0];function d(){b.textContent="Link copied";setTimeout(function(){b.textContent=t;},1800);}if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(u).then(d,function(){prompt("",u);});}else{prompt("",u);}});})();</script><div class="yj-home-find"><div class="yj-lgbar"><a href="/" class="yj-lg on">EN</a><a href="/de/" class="yj-lg">DE</a><a href="/ja/" class="yj-lg">JA</a><a href="/es/" class="yj-lg">ES</a><a href="/pt/" class="yj-lg">PT</a></div><section class="yj-find"><h2>Find a tool</h2><input id="yjq" type="search" autocomplete="off" placeholder="Type a product name, format or task"><div id="yjr"></div></section><style>.yj-lgbar{position:absolute;top:14px;right:18px;display:flex;gap:6px;z-index:60}.yj-lg{font:600 12px/1 system-ui,sans-serif;padding:6px 9px;border-radius:4px;text-decoration:none;color:#8b96a3;border:1px solid rgba(140,150,165,.28)}.yj-lg:hover{color:#e8eaed;border-color:rgba(160,175,195,.6)}.yj-lg.on{color:#0e1116;background:#cfd6de;border-color:#cfd6de}.yj-find{max-width:760px;margin:34px auto 8px;padding:0 20px}.yj-find h2{font:600 20px/1.3 system-ui,sans-serif;margin:0 0 10px}#yjq{width:100%;box-sizing:border-box;padding:13px 15px;font:400 15.5px system-ui,sans-serif;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:rgba(255,255,255,.04);color:inherit}#yjq:focus{outline:none;border-color:#7FD1C4}#yjr{margin-top:10px;display:flex;flex-direction:column;gap:6px}#yjr a{display:flex;justify-content:space-between;gap:12px;padding:11px 14px;border:1px solid rgba(140,150,165,.22);border-radius:6px;text-decoration:none;font:400 14.5px/1.4 system-ui,sans-serif;color:inherit}#yjr a:hover{border-color:#7FD1C4}#yjr .pr{font:600 13px system-ui,sans-serif;color:#5fbf9a;white-space:nowrap}</style><script>(function(){var q=document.getElementById("yjq"),r=document.getElementById("yjr"),D=null;function load(){if(D)return Promise.resolve(D);return fetch("/search-index.json").then(function(x){return x.json();}).then(function(j){D=j;return j;}).catch(function(){D=[];return D;});}function esc(t){return String(t).replace(/[&<>"]/g,function(c){return {"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"}[c];});}function run(){var v=q.value.trim().toLowerCase();if(v.length<2){r.innerHTML="";return;}load().then(function(j){var w=v.split(/\s+/),o=[];for(var i=0;i<j.length&&o.length<12;i++){var t=j[i].t.toLowerCase();var ok=true;for(var k=0;k<w.length;k++){if(t.indexOf(w[k])<0){ok=false;break;}}if(ok)o.push(j[i]);}r.innerHTML=o.length?o.map(function(x){return "<a href=\""+esc(x.u)+"\">"+"<span>"+esc(x.t)+"</span>"+(x.p?"<span class=\"pr\">$"+x.p+"</span>":"")+"</a>";}).join(""):"";});}q.addEventListener("input",run);q.addEventListener("focus",load);})();</script></div>
280
+ <script data-yj="yj-view-beacon">(function(){try{var p=location.pathname;var k='yjv:'+p;if(sessionStorage.getItem(k))return;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",ref:(document.referrer||'')})}).catch(function(){});}catch(e){}})();</script>
281
+ </body>
282
  </html>