-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
668 lines (624 loc) · 40.1 KB
/
Copy pathindex.html
File metadata and controls
668 lines (624 loc) · 40.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CORETEXA — Can this pull request's own tests actually fail?</title>
<meta name="description" content="A pull request says it fixes a bug and adds tests. coretexa-verify puts the source back the way it was, keeps the new tests, and runs them again. If they still pass, the tests were never a gate. Free GitHub Action, runs on your runner, MIT.">
<link rel="canonical" href="https://coretexa.dev/">
<meta property="og:site_name" content="Coretexa">
<meta property="og:type" content="website">
<meta property="og:url" content="https://coretexa.dev/">
<meta property="og:title" content="Coretexa — can this pull request's own tests actually fail?">
<meta property="og:description" content="Revert the source, keep the pull request's new tests, run them again. A test that still passes without the fix was never a gate. Free GitHub Action, runs on your runner. MIT.">
<meta property="og:image" content="https://coretexa.dev/og.png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt" content="Coretexa — the agent that does the work can’t close it.">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@fezystockmarke1">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
:root{
--ground:#071a30;
--ground-2:#0b2545;
--paper:#0a2138;
--line:#18456e;
--line-2:#1f5688;
--hair:rgba(120,180,230,.16);
--cyan:#22d3ee;
--cyan-dim:#0e7f96;
--amber:#f5b642;
--white:#eaf4fb;
--ink:#a8c6de;
--ink-dim:#6c93b4;
--ok:#3ddc97;
--bad:#ff5d73;
--mono:'IBM Plex Mono',ui-monospace,monospace;
--sans:'Space Grotesk',system-ui,sans-serif;
--maxw:1180px;
}
*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth}
body{
font-family:var(--sans);
background:var(--ground);
color:var(--ink);
line-height:1.55;
-webkit-font-smoothing:antialiased;
overflow-x:hidden;
position:relative;
}
/* graph-paper background */
body::before{
content:"";
position:fixed;inset:0;z-index:-2;
background:
linear-gradient(var(--hair) 1px,transparent 1px) 0 0/26px 26px,
linear-gradient(90deg,var(--hair) 1px,transparent 1px) 0 0/26px 26px,
linear-gradient(rgba(120,180,230,.05) 1px,transparent 1px) 0 0/130px 130px,
linear-gradient(90deg,rgba(120,180,230,.05) 1px,transparent 1px) 0 0/130px 130px,
radial-gradient(ellipse at 50% -10%,#0d2c4d 0%,var(--ground) 60%);
pointer-events:none;
}
body::after{
content:"";
position:fixed;inset:0;z-index:-1;
background:radial-gradient(ellipse at 50% 40%,transparent 55%,rgba(3,10,20,.55) 100%);
pointer-events:none;
}
a{color:inherit;text-decoration:none}
::selection{background:var(--cyan);color:var(--ground)}
.wrap{max-width:var(--maxw);margin:0 auto;padding:0 28px}
.mono{font-family:var(--mono)}
.label{font-family:var(--mono);font-size:11px;letter-spacing:.18em;text-transform:uppercase;color:var(--cyan-dim)}
/* ---- dimension-line section headers ---- */
.sec-tag{
display:inline-flex;align-items:center;gap:10px;
font-family:var(--mono);font-size:11px;letter-spacing:.22em;text-transform:uppercase;
color:var(--cyan);margin-bottom:20px;
}
.sec-tag::before{content:"";width:34px;height:1px;background:var(--cyan);opacity:.6}
.sec-tag .num{color:var(--amber)}
h1,h2,h3{font-weight:600;color:var(--white);line-height:1.08;letter-spacing:-.01em}
section{padding:96px 0;position:relative}
.divider{max-width:var(--maxw);margin:0 auto;height:1px;background:linear-gradient(90deg,transparent,var(--line),transparent)}
/* =========== NAV =========== */
nav{
position:sticky;top:0;z-index:50;
backdrop-filter:blur(10px);
background:rgba(7,26,48,.72);
border-bottom:1px solid var(--hair);
}
.nav-in{max-width:var(--maxw);margin:0 auto;padding:14px 28px;display:flex;align-items:center;gap:24px}
.brand{display:flex;align-items:center;gap:12px;font-weight:700;letter-spacing:.14em;color:var(--white);font-size:15px}
.brand .glyph{width:22px;height:22px;flex:none}
.nav-links{display:flex;gap:26px;margin-left:auto;font-family:var(--mono);font-size:13px}
.nav-links a{color:var(--ink);transition:color .18s;position:relative}
.nav-links a:hover{color:var(--cyan)}
.nav-links a::after{content:"";position:absolute;left:0;bottom:-5px;width:0;height:1px;background:var(--cyan);transition:width .2s}
.nav-links a:hover::after{width:100%}
.tag-mit{font-family:var(--mono);font-size:11px;color:var(--ink-dim);border:1px solid var(--hair);padding:3px 8px;border-radius:3px;letter-spacing:.08em}
.btn{
font-family:var(--mono);font-size:13px;font-weight:500;
display:inline-flex;align-items:center;gap:8px;
padding:9px 16px;border-radius:5px;cursor:pointer;transition:.18s;white-space:nowrap;
}
.btn-primary{background:var(--cyan);color:#04121f;border:1px solid var(--cyan);font-weight:600}
.btn-primary:hover{background:#5fe4f6;box-shadow:0 0 20px rgba(34,211,238,.35)}
.btn-ghost{background:transparent;color:var(--white);border:1px solid var(--line-2)}
.btn-ghost:hover{border-color:var(--cyan);color:var(--cyan)}
.nav-toggle{display:none;margin-left:auto;background:none;border:1px solid var(--line-2);color:var(--white);border-radius:5px;padding:7px 10px;cursor:pointer}
/* =========== HERO =========== */
.hero{padding:88px 0 72px;position:relative}
.hero-grid{display:grid;grid-template-columns:1.05fr .95fr;gap:56px;align-items:center}
.hero .kicker{margin-bottom:22px}
.hero h1{font-size:clamp(36px,5vw,60px);letter-spacing:-.02em;margin-bottom:22px}
.hero h1 .hl{color:var(--cyan)}
.hero p.sub{font-size:18px;max-width:560px;margin-bottom:18px;color:var(--ink)}
.hero .worksline{font-family:var(--mono);font-size:12.5px;color:var(--ink-dim);margin-bottom:30px}
.hero .worksline .ok{color:var(--ok)}
.hero-cta{display:flex;gap:14px;flex-wrap:wrap}
.btn-lg{padding:13px 22px;font-size:14px}
/* mini schematic in hero */
.hero-card{
border:1px solid var(--line);border-radius:10px;
background:linear-gradient(160deg,rgba(11,37,69,.75),rgba(7,26,48,.55));
padding:22px;position:relative;overflow:hidden;
}
.hero-card::before{content:"SPEC-01 / NO-SELF-CLOSE";position:absolute;top:12px;right:14px;font-family:var(--mono);font-size:9.5px;letter-spacing:.16em;color:var(--cyan-dim)}
.corner{position:absolute;width:12px;height:12px;border:1px solid var(--cyan);opacity:.5}
.corner.tl{top:8px;left:8px;border-right:0;border-bottom:0}
.corner.tr{top:8px;right:8px;border-left:0;border-bottom:0}
.corner.bl{bottom:8px;left:8px;border-right:0;border-top:0}
.corner.br{bottom:8px;right:8px;border-left:0;border-top:0}
/* =========== PROBLEM =========== */
.problem-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:22px;margin-top:14px}
.pcard{
border:1px solid var(--hair);border-radius:9px;padding:26px 24px;
background:rgba(10,33,56,.4);position:relative;transition:.2s;
}
.pcard:hover{border-color:var(--line-2);transform:translateY(-3px)}
.pcard .idx{font-family:var(--mono);font-size:12px;color:var(--amber);margin-bottom:16px;display:block}
.pcard h3{font-size:18px;margin-bottom:10px}
.pcard p{font-size:14.5px;color:var(--ink-dim)}
.problem-lead{font-size:22px;color:var(--white);max-width:760px;margin-bottom:10px;font-weight:500;line-height:1.35}
.problem-lead .q{color:var(--cyan)}
/* =========== HOW IT WORKS / PIPELINE =========== */
.diagram-shell{
border:1px solid var(--line);border-radius:12px;
background:linear-gradient(180deg,rgba(9,30,52,.6),rgba(7,22,40,.35));
padding:26px 22px 20px;margin-top:8px;position:relative;
}
.diagram-head{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:8px;flex-wrap:wrap;gap:8px}
.diagram-head .t{font-family:var(--mono);font-size:11px;letter-spacing:.16em;color:var(--cyan-dim)}
.svg-scroll{width:100%;overflow:hidden}
svg.pipeline{display:block;width:100%;height:auto}
.pipe-mobile{display:none}
.pipe-mobile svg{max-width:360px;margin:6px auto 0;display:block}
.legend{display:flex;gap:22px;flex-wrap:wrap;margin-top:16px;font-family:var(--mono);font-size:11.5px;color:var(--ink-dim)}
.legend span{display:inline-flex;align-items:center;gap:7px}
.legend i{width:10px;height:10px;border-radius:2px;display:inline-block}
/* =========== FIVE GATES =========== */
.gates{display:grid;grid-template-columns:repeat(5,1fr);gap:16px;margin-top:14px;counter-reset:g}
.gate{
border:1px solid var(--hair);border-top:2px solid var(--cyan);
border-radius:8px;padding:22px 18px;background:rgba(10,33,56,.35);
position:relative;transition:.2s;
}
.gate:hover{background:rgba(14,42,70,.6);transform:translateY(-3px)}
.gate .gn{font-family:var(--mono);font-size:12px;color:var(--cyan);margin-bottom:14px;display:block}
.gate h4{font-size:15px;color:var(--white);font-weight:600;line-height:1.3;margin-bottom:6px}
.gate p{font-size:13px;color:var(--ink-dim)}
.gate.g5{border-top-color:var(--amber)}
.gate.g5 .gn{color:var(--amber)}
/* =========== NO SELF CLOSE =========== */
.nsc-grid{display:grid;grid-template-columns:1fr 1.15fr;gap:44px;align-items:center}
.nsc h2{font-size:clamp(28px,3.4vw,40px);margin-bottom:20px}
.nsc h2 .no{color:var(--bad)}
.nsc p{font-size:16px;color:var(--ink);margin-bottom:16px;max-width:460px}
.nsc .enforced{font-family:var(--mono);font-size:13px;color:var(--white);border-left:2px solid var(--amber);padding-left:14px}
.term{
border:1px solid var(--line);border-radius:10px;overflow:hidden;
background:#04121f;font-family:var(--mono);font-size:13px;box-shadow:0 24px 60px -30px rgba(0,0,0,.8);
}
.term-bar{display:flex;align-items:center;gap:7px;padding:11px 15px;background:#081f36;border-bottom:1px solid var(--line)}
.term-bar i{width:11px;height:11px;border-radius:50%;display:inline-block}
.term-bar .t{margin-left:10px;font-size:11px;color:var(--ink-dim);letter-spacing:.05em}
.term-body{padding:18px 18px 20px;line-height:1.85;overflow-x:auto}
.term-body .l{white-space:pre;display:block}
.c-prompt{color:var(--cyan)}
.c-cmd{color:var(--white)}
.c-flag{color:var(--amber)}
.c-str{color:var(--ok)}
.c-com{color:var(--ink-dim)}
.c-key{color:#8ab4ff}
.c-bad{color:var(--bad);font-weight:600}
.c-ok{color:var(--ok);font-weight:600}
.c-dim{color:var(--ink-dim)}
/* =========== BEYOND TICKETS =========== */
.beyond-grid{display:grid;grid-template-columns:1fr 1fr;gap:26px;margin-top:14px}
.bcard{border:1px solid var(--hair);border-radius:11px;padding:30px 28px;background:rgba(10,33,56,.4);position:relative;overflow:hidden}
.bcard h3{font-size:20px;margin-bottom:12px;display:flex;align-items:center;gap:10px}
.bcard h3 .badge{font-family:var(--mono);font-size:10px;letter-spacing:.1em;color:var(--amber);border:1px solid var(--amber);border-radius:3px;padding:2px 7px}
.bcard p{font-size:14.5px;color:var(--ink-dim);margin-bottom:20px}
.tree-wrap{width:100%;overflow-x:auto}
svg.tree{display:block;width:100%;height:auto;min-width:300px}
.tree-note{font-family:var(--mono);font-size:11px;color:var(--ink-dim);margin-top:12px;line-height:1.6}
.tree-note b{color:var(--amber)}
/* =========== PROOF =========== */
.proof{text-align:center}
.stats{display:grid;grid-template-columns:repeat(3,1fr);gap:0;margin:34px auto 0;max-width:820px;border:1px solid var(--line);border-radius:12px;overflow:hidden}
.stat{padding:38px 20px;position:relative;background:rgba(9,30,52,.4)}
.stat + .stat{border-left:1px solid var(--line)}
.stat .num{font-family:var(--mono);font-size:clamp(40px,6vw,58px);font-weight:600;color:var(--cyan);line-height:1;letter-spacing:-.02em}
.stat.amber .num{color:var(--amber)}
.stat .cap{font-family:var(--mono);font-size:12px;color:var(--ink-dim);margin-top:12px;letter-spacing:.04em}
.stat .dim-line{position:absolute;top:20px;left:16px;right:16px;height:1px;border-top:1px dashed var(--hair)}
.proof-quote{font-size:19px;color:var(--white);max-width:680px;margin:0 auto 6px;font-weight:500;line-height:1.4}
.proof-sub{font-family:var(--mono);font-size:13px;color:var(--ink-dim);max-width:620px;margin:14px auto 0}
/* =========== QUICK START =========== */
.qs-grid{display:grid;grid-template-columns:.85fr 1.15fr;gap:40px;align-items:start}
.steps{list-style:none;counter-reset:s}
.steps li{position:relative;padding:0 0 26px 46px;border-left:1px dashed var(--line);margin-left:16px}
.steps li:last-child{border-left-color:transparent;padding-bottom:0}
.steps li::before{
counter-increment:s;content:counter(s,decimal-leading-zero);
position:absolute;left:-16px;top:-4px;width:32px;height:32px;border-radius:50%;
background:var(--ground);border:1px solid var(--cyan);color:var(--cyan);
font-family:var(--mono);font-size:12px;display:flex;align-items:center;justify-content:center;
}
.steps li h4{font-size:16px;color:var(--white);margin-bottom:5px;font-weight:600}
.steps li p{font-size:14px;color:var(--ink-dim)}
.steps li code{font-family:var(--mono);font-size:12.5px;color:var(--amber);background:rgba(245,182,66,.08);padding:1px 5px;border-radius:3px}
/* =========== FINAL CTA =========== */
.final{text-align:center;padding:100px 0}
.final h2{font-size:clamp(30px,4vw,46px);margin-bottom:20px}
.final p{font-size:17px;color:var(--ink);max-width:560px;margin:0 auto 30px}
.final-cta{display:flex;gap:14px;justify-content:center;flex-wrap:wrap}
.honest{font-family:var(--mono);font-size:12.5px;color:var(--ink-dim);margin-top:26px}
/* =========== FOOTER =========== */
footer{border-top:1px solid var(--hair);padding:34px 0;font-family:var(--mono);font-size:12.5px;color:var(--ink-dim)}
.foot-in{max-width:var(--maxw);margin:0 auto;padding:0 28px;display:flex;flex-wrap:wrap;gap:16px;align-items:center;justify-content:space-between}
.foot-in .dot{color:var(--line-2)}
footer a:hover{color:var(--cyan)}
/* reveal */
.reveal{opacity:0;transform:translateY(22px);transition:opacity .7s cubic-bezier(.2,.7,.2,1),transform .7s cubic-bezier(.2,.7,.2,1)}
.reveal.in{opacity:1;transform:none}
/* SVG animation classes */
.flow-path{stroke-dasharray:6 5;animation:march 1.1s linear infinite}
@keyframes march{to{stroke-dashoffset:-22}}
.node-pulse{animation:nodeGlow 2.6s ease-in-out infinite}
@keyframes nodeGlow{0%,100%{opacity:.55}50%{opacity:1}}
.reject-x{animation:rejBlink 2.2s steps(1) infinite}
@keyframes rejBlink{0%,60%{opacity:1}80%,100%{opacity:.25}}
@media (prefers-reduced-motion:reduce){
html{scroll-behavior:auto}
.flow-path{animation:none;stroke-dashoffset:0}
.node-pulse{animation:none;opacity:1}
.reject-x{animation:none;opacity:1}
#token{display:none}
.reveal{opacity:1;transform:none;transition:none}
}
/* ============ RESPONSIVE ============ */
@media(max-width:960px){
.hero-grid{grid-template-columns:1fr;gap:36px}
.nsc-grid{grid-template-columns:1fr;gap:30px}
.qs-grid{grid-template-columns:1fr;gap:30px}
.beyond-grid{grid-template-columns:1fr}
.problem-grid{grid-template-columns:1fr}
.gates{grid-template-columns:repeat(2,1fr)}
}
@media(max-width:640px){
section{padding:64px 0}
.wrap{padding:0 18px}
.nav-links,.tag-mit,.btn-primary.desk{display:none}
.nav-toggle{display:inline-flex}
nav.open .nav-links{display:flex;position:absolute;top:57px;left:0;right:0;flex-direction:column;gap:0;background:var(--ground-2);border-bottom:1px solid var(--line);padding:8px 0}
nav.open .nav-links a{padding:13px 28px;border-top:1px solid var(--hair)}
nav.open .nav-links a::after{display:none}
.hero{padding:54px 0 40px}
.stats{grid-template-columns:1fr}
.stat + .stat{border-left:0;border-top:1px solid var(--line)}
.gates{grid-template-columns:1fr}
.hero-cta .btn,.final-cta .btn{flex:1;justify-content:center}
.foot-in{flex-direction:column;text-align:center;gap:10px}
.pipe-desktop{display:none}
.pipe-mobile{display:block}
}
/* ---- nav fits between the mobile menu and full desktop ----
Between 640px and ~900px the links were still shown alongside the
licence chip and the CTA, which pushed the bar past the viewport. */
@media(max-width:900px){ .tag-mit{display:none} }
@media(max-width:830px){
.btn-primary.desk{display:none}
.nav-links{gap:18px;font-size:12.5px}
}
/* ---- grid children must be allowed to shrink ----
Grid items default to `min-width:auto`, so a terminal block full of
`white-space:pre` lines sets the column's floor at its intrinsic width
and widens the whole page on a phone. The `overflow-x:auto` on the
terminal body only helps once the column itself can get narrower. */
.hero-grid>*,.qs-grid>*,.nsc-grid>*{min-width:0}
.term{max-width:100%}
/* ---- section rhythm ----
`.wrap` (a class) outranks the bare `section` type selector, so
`section{padding:96px 0}` never applied to `<section class="wrap">`
and every band collapsed to zero vertical padding. Restore it at a
specificity that actually wins, keeping the horizontal gutter. */
section.wrap{padding:96px 28px}
header.hero.wrap{padding:88px 28px 72px}
section.final.wrap{padding:100px 28px}
@media(max-width:720px){
section.wrap{padding:64px 22px}
header.hero.wrap{padding:56px 22px 48px}
section.final.wrap{padding:72px 22px}
}
/* ---- verdict cards ---- */
.gate.v-bad{border-top-color:var(--bad)} .gate.v-bad .gn{color:var(--bad)}
.gate.v-ok{border-top-color:var(--ok)} .gate.v-ok .gn{color:var(--ok)}
.gate.v-dim{border-top-color:var(--ink-dim)} .gate.v-dim .gn{color:var(--ink-dim)}
.gate code{font-family:var(--mono);font-size:12.5px}
/* ---- cannot list ---- */
.cannot{display:grid;grid-template-columns:repeat(2,1fr);gap:18px;margin-top:22px}
.cannot li{list-style:none;border-left:2px solid var(--bad);padding:2px 0 2px 16px;font-size:14.5px;color:var(--ink-dim)}
.cannot li b{color:var(--white);font-weight:600;display:block;margin-bottom:3px;font-size:15px}
/* ---- catch card ---- */
.catch{border:1px solid var(--line);border-radius:11px;background:rgba(10,33,56,.42);padding:0;overflow:hidden}
.catch .ch{padding:22px 26px;border-bottom:1px solid var(--hair);display:flex;flex-wrap:wrap;align-items:center;gap:14px}
.catch .ch .verd{font-family:var(--mono);font-size:11px;letter-spacing:.14em;color:var(--bad);border:1px solid var(--bad);border-radius:3px;padding:3px 9px}
.catch .ch .verd.fixed{color:var(--ok);border-color:var(--ok)}
.catch .ch .repo{font-family:var(--mono);font-size:13px;color:var(--white)}
.catch .cb{padding:24px 26px}
.catch .cb p{font-size:15px;color:var(--ink);margin-bottom:16px}
.catch .cb p:last-child{margin-bottom:0}
.catch .cb .epi{font-size:14px;color:var(--ink-dim);border-left:2px solid var(--amber);padding-left:14px;margin-top:20px}
.catch .cb .epi b{color:var(--white)}
.langs{display:flex;gap:10px;flex-wrap:wrap;margin-top:26px;font-family:var(--mono);font-size:12px}
.langs span{border:1px solid var(--hair);border-radius:4px;padding:5px 11px;color:var(--ink)}
.langs span.exp{color:var(--ink-dim)}
@media(max-width:860px){.cannot{grid-template-columns:1fr}}
</style>
</head>
<body id="top">
<nav id="nav">
<div class="nav-in">
<a href="#top" class="brand">
<svg class="glyph" viewBox="0 0 24 24" fill="none" stroke="var(--cyan)" stroke-width="1.6">
<rect x="3" y="3" width="18" height="18" rx="2"/>
<path d="M7 12.5l3 3 7-7" stroke="var(--amber)" stroke-width="1.8"/>
</svg>
CORETEXA
</a>
<span class="tag-mit">MIT · open source</span>
<div class="nav-links">
<a href="#how">How it works</a>
<a href="#verdicts">Verdicts</a>
<a href="#start">Quick start</a>
<a href="/proof.html">Proof</a>
<a href="/blog.html">Writing</a>
<a href="https://github.com/earfman/coretexa-verify" target="_blank" rel="noopener">GitHub</a>
<a href="mailto:hello@coretexa.dev">Ask</a>
</div>
<a href="https://github.com/marketplace/actions/coretexa-verify" target="_blank" rel="noopener" class="btn btn-primary desk">Get it</a>
<button class="nav-toggle" id="navToggle" aria-label="Menu">≡</button>
</div>
</nav>
<!-- ================= HERO ================= -->
<header class="hero wrap">
<div class="hero-grid">
<div>
<div class="sec-tag kicker">Mutation check for pull requests</div>
<h1>Can this pull request’s own tests <span class="hl">actually fail?</span></h1>
<p class="sub">A pull request says it fixes a bug and adds tests. Coretexa puts the source code back the way it was, leaves the new tests exactly where they are, and runs them again. If they still pass, the tests do not touch the thing the pull request changed — and you know that before you merge, not six months later.</p>
<p class="worksline">runs on <span class="ok">your</span> runner — nothing executes on our infrastructure · no runtime dependencies of its own · no telemetry · MIT</p>
<div class="hero-cta">
<a href="https://github.com/marketplace/actions/coretexa-verify" target="_blank" rel="noopener" class="btn btn-primary btn-lg">Get it on the Marketplace</a>
<a href="/proof.html" class="btn btn-ghost btn-lg">See what it caught</a>
</div>
</div>
<div>
<div class="term" style="font-size:12.5px">
<div class="term-bar"><i style="background:#ff5f57"></i><i style="background:#febc2e"></i><i style="background:#28c840"></i><span class="t">real output · ioi-isr/cms #174</span></div>
<div class="term-body">
<span class="l"><span class="c-bad">[!!] NO_GATE</span></span>
<span class="l"></span>
<span class="l"><span class="c-com">3 of 5 behavioural changes in this PR can be</span></span>
<span class="l"><span class="c-com">reverted with all 5 of its tests still passing.</span></span>
<span class="l"></span>
<span class="l"><span class="c-cmd">run at head</span> <span class="c-str">PASS</span> <span class="c-com">— 5 passed</span></span>
<span class="l"><span class="c-cmd">run w/ source reverted</span> <span class="c-str">PASS</span> <span class="c-com">— 5 passed</span> <span class="c-flag">← the finding</span></span>
</div>
</div>
<p class="mono" style="font-size:11.5px;color:var(--ink-dim);margin-top:12px;text-align:right">a live, unmodified verdict — not a mock-up</p>
<p class="mono" style="font-size:12px;color:var(--ink-dim);margin-top:22px;text-align:right;line-height:1.8">the same discipline, applied to our own work:<br><b style="color:var(--ok)">7 fixes merged upstream</b> — <a href="https://github.com/google/gson/pull/3059" target="_blank" rel="noopener" style="color:var(--ink)">gson</a>, <a href="https://github.com/bazelbuild/buildtools/pull/1481" target="_blank" rel="noopener" style="color:var(--ink)">buildtools</a>, <a href="https://github.com/PrefectHQ/fastmcp/pull/4517" target="_blank" rel="noopener" style="color:var(--ink)">fastmcp</a>, <a href="https://github.com/VirtusLab/git-machete/pull/1755" target="_blank" rel="noopener" style="color:var(--ink)">git-machete</a>, <a href="https://github.com/Sollumz/szio/pull/2" target="_blank" rel="noopener" style="color:var(--ink)">szio</a>, <a href="https://github.com/pallets-eco/croniter/pull/246" target="_blank" rel="noopener" style="color:var(--ink)">croniter</a>, <a href="https://github.com/yorukot/superfile/pull/1552" target="_blank" rel="noopener" style="color:var(--ink)">superfile</a></p>
</div>
</div>
</header>
<div class="divider"></div>
<!-- ================= PROBLEM ================= -->
<section class="wrap" id="problem">
<div class="sec-tag"><span class="num">01</span> The problem</div>
<p class="problem-lead">Agent-written pull requests arrive green. <span class="q">Green is not evidence.</span></p>
<p style="max-width:760px;color:var(--ink-dim);font-size:16px">A passing suite tells you the tests passed. It does not tell you the tests would have failed without the fix — and that is the only property that makes a test a gate.</p>
<div class="problem-grid">
<div class="pcard reveal">
<span class="idx">BEAT 01</span>
<h3>The test covers the wrong thing</h3>
<p>The new test exercises the tidy helper function the change added, not the one line that wires it into the program. Delete the wiring and the test is still green.</p>
</div>
<div class="pcard reveal">
<span class="idx">BEAT 02</span>
<h3>The suite was quietly weakened</h3>
<p>An assertion loosened, a case skipped, a threshold widened. CI goes green because the bar moved, not because the bug went away.</p>
</div>
<div class="pcard reveal">
<span class="idx">BEAT 03</span>
<h3>The author graded the work</h3>
<p>The thing that wrote the fix also wrote the test that proves the fix. That is not review — it is a rubber stamp with extra steps.</p>
</div>
</div>
</section>
<div class="divider"></div>
<!-- ================= HOW IT WORKS ================= -->
<section class="wrap" id="how">
<div class="sec-tag"><span class="num">02</span> How it works</div>
<h2 style="font-size:clamp(26px,3.2vw,38px);margin-bottom:14px">One experiment, run on every pull request.</h2>
<p style="max-width:720px;color:var(--ink-dim);font-size:16px;margin-bottom:34px">There is no model in it, and on a standard project there is nothing to configure. It answers one question by running something, and everything it reports it established by observation.</p>
<div class="qs-grid">
<ol class="steps">
<li>
<h4>Split the diff</h4>
<p>Source changes on one side, new and modified tests on the other. Renames, docs, lockfiles and assets are classified and set aside.</p>
</li>
<li>
<h4>Put the source back</h4>
<p>Every behavioural hunk is reverted to the merge base at once. That is two test runs and usually the whole story. Only when the revert fails to <em>compile</em> — common in Go, Rust and Java — does it fall back to reverting each hunk on its own, so the verdict still points at a line rather than a pull request. That second stage is bounded by a time budget you control.</p>
</li>
<li>
<h4>Run the pull request’s own tests</h4>
<p>Unchanged, exactly as the author wrote them. If they fail, the tests genuinely gate the change. If they pass, they never did.</p>
</li>
</ol>
<div class="term" style="font-size:12.5px">
<div class="term-bar"><i style="background:#ff5f57"></i><i style="background:#febc2e"></i><i style="background:#28c840"></i><span class="t">per-hunk localisation</span></div>
<div class="term-body">
<span class="l"><span class="c-com">per-hunk localisation (each hunk reverted on its own)</span></span>
<span class="l"> <span class="c-str">GATED</span> <span class="c-cmd">config/web/web.go</span> hunk 4</span>
<span class="l"> <span class="c-com">ASSERT_FAIL: 62 passed, 1 failed</span></span>
<span class="l"> <span class="c-dim">-> TestGetDefaultConfig</span></span>
<span class="l"> <span class="c-bad">UNGATED</span> <span class="c-cmd">config/config.go</span> hunk 1</span>
<span class="l"> <span class="c-com">PASS: 63 passed</span> <span class="c-flag">← nothing noticed</span></span>
<span class="l"> <span class="c-dim">UNREACHED</span> <span class="c-cmd">web/app/src/App.vue</span> hunk 1</span>
<span class="l"> <span class="c-com">not run — the Go runner cannot observe this file</span></span>
</div>
</div>
</div>
</section>
<div class="divider"></div>
<!-- ================= VERDICTS ================= -->
<section class="wrap" id="verdicts">
<div class="sec-tag"><span class="num">03</span> The verdicts</div>
<h2 style="font-size:clamp(26px,3.2vw,38px);margin-bottom:14px">Five answers. It refuses to guess between them.</h2>
<p style="max-width:720px;color:var(--ink-dim);font-size:16px">A finding is only reported when the mapping from test to code was <em>proved</em>, not inferred. When it cannot prove one, it says so instead of picking the interesting answer.</p>
<div class="gates">
<div class="gate v-bad reveal">
<span class="gn">[!!]</span>
<h4><code>NO_GATE</code></h4>
<p>A behavioural change can be reverted with the pull request’s own tests still passing. The tests do not detect the fix.</p>
</div>
<div class="gate v-ok reveal">
<span class="gn">[ok]</span>
<h4><code>GATE_HOLDS</code></h4>
<p>Reverting the source makes the new tests fail. They really do gate the change. This is the good case, and the common one.</p>
</div>
<div class="gate v-ok reveal">
<span class="gn">[ok]</span>
<h4><code>GATE_HOLDS_BUILD</code></h4>
<p>The revert does not compile, so the change is load-bearing at build time. Weaker evidence than a failing assertion, and labelled as such.</p>
</div>
<div class="gate v-dim reveal">
<span class="gn">[--]</span>
<h4><code>NO_NEW_TESTS</code></h4>
<p>There is nothing to run. The pull request changes behaviour and adds no test that could observe it.</p>
</div>
<div class="gate v-dim reveal">
<span class="gn">[??]</span>
<h4><code>INCONCLUSIVE</code></h4>
<p>The experiment could not be run cleanly. Reported honestly, with the reason, rather than dressed up as a pass.</p>
</div>
</div>
<div class="langs">
<span>Python</span><span>JavaScript / TypeScript</span><span>Go</span><span>Rust</span><span class="exp">Java (experimental)</span><span class="exp">anything else via <code>test-command</code></span>
</div>
</section>
<div class="divider"></div>
<!-- ================= QUICK START ================= -->
<section class="wrap" id="start">
<div class="sec-tag"><span class="num">04</span> Quick start</div>
<h2 style="font-size:clamp(26px,3.2vw,38px);margin-bottom:14px">Paste one file. There is no step two.</h2>
<p style="max-width:720px;color:var(--ink-dim);font-size:16px;margin-bottom:34px">No account, no API key, no service to sign up for. Coretexa itself is pure Python standard library and pulls in nothing of its own — it detects and installs <em>your</em> project’s declared test dependencies on your runner, because it has to run your tests.</p>
<div class="term" style="font-size:12.5px;max-width:820px">
<div class="term-bar"><i style="background:#ff5f57"></i><i style="background:#febc2e"></i><i style="background:#28c840"></i><span class="t">.github/workflows/coretexa-verify.yml</span></div>
<div class="term-body">
<span class="l"><span class="c-key">name</span>: coretexa-verify</span>
<span class="l"><span class="c-key">on</span>: pull_request</span>
<span class="l"></span>
<span class="l"><span class="c-key">permissions</span>:</span>
<span class="l"> <span class="c-key">contents</span>: read</span>
<span class="l"></span>
<span class="l"><span class="c-key">jobs</span>:</span>
<span class="l"> <span class="c-key">verify</span>:</span>
<span class="l"> <span class="c-key">runs-on</span>: ubuntu-latest</span>
<span class="l"> <span class="c-key">steps</span>:</span>
<span class="l"> - <span class="c-key">uses</span>: actions/checkout@v4</span>
<span class="l"> <span class="c-key">with</span>:</span>
<span class="l"> <span class="c-key">fetch-depth</span>: 0 <span class="c-com"># we need the merge base</span></span>
<span class="l"> - <span class="c-key">uses</span>: <span class="c-str">earfman/coretexa-verify@v1</span></span>
</div>
</div>
<p class="mono" style="font-size:12.5px;color:var(--ink-dim);margin-top:18px">Read-only. The verdict goes to the job summary, so nothing needs write access — the safest thing to run on a public repo that takes fork pull requests. Want it as a PR comment instead? Add <span style="color:var(--amber)">pull-requests: write</span> and pass <span style="color:var(--amber)">github-token</span>. Non-blocking by default — it only fails the job if you opt in with <span style="color:var(--amber)">fail-on</span>.</p>
</section>
<div class="divider"></div>
<!-- ================= A REAL CATCH ================= -->
<section class="wrap" id="catch">
<div class="sec-tag"><span class="num">05</span> A real catch</div>
<h2 style="font-size:clamp(26px,3.2vw,38px);margin-bottom:26px">Three rounds of AI review. No test touched the new code.</h2>
<div class="catch reveal">
<div class="ch">
<span class="verd">NO_GATE · reproduced</span>
<span class="repo">yorukot/superfile #1545</span>
<span class="mono" style="font-size:12px;color:var(--ink-dim)">“feat(metadata): cache directory size calculations”</span>
</div>
<div class="cb">
<p>The pull request did two things: it added a directory-size cache, and it added request tracking to keep stale results from being applied to the wrong path. The cache was well tested. The request tracking was not tested at all — and nothing in the review caught it, because a passing suite looks the same either way.</p>
<div class="term" style="font-size:12px">
<div class="term-body">
<span class="l"><span class="c-com"># put the request-tracking hunks back the way they were, keep every new test</span></span>
<span class="l"><span class="c-cmd">reverted:</span> model.go L148-155, L162-174 · model_msg.go L172-182</span>
<span class="l"><span class="c-cmd">tests:</span> <span class="c-ok">67 passed</span>, <span class="c-dim">0 failed</span></span>
<span class="l"><span class="c-cmd">grep across *_test.go:</span> <span class="c-bad">no match</span> <span class="c-dim">for IsPending, IsFresh, SetPendingRequest, MatchPendingRequest, ClearPendingRequest</span></span>
<span class="l"></span>
<span class="l"><span class="c-bad">NO_GATE</span> <span class="c-dim">— the new tests do not detect the new code</span></span>
</div>
</div>
<p>Five new symbols, none of them named in a single test file. Revert all three hunks and the suite is still green, so the change could break in any future edit and nothing would say so.</p>
<p class="epi">CodeRabbit had reviewed this pull request three times and posted rounds of design opinions on exactly that code. It never mentioned that the code had no tests. That is the gap this check is for: not whether the code is good, but whether anything would notice if it stopped working.</p>
<p class="epi">The contributor added <code class="mono">request_tracking_test.go</code> plus integration tests the next day — and while writing them, found and fixed a stale-response bug on the same path that our report had not named. That is the intended shape of this: the check points at an untested change, and the person who wrote it does the rest.</p>
</div>
</div>
</section>
<div class="divider"></div>
<!-- ================= WHAT IT CANNOT DO ================= -->
<section class="wrap" id="cannot">
<div class="sec-tag"><span class="num">06</span> What it cannot tell you</div>
<h2 style="font-size:clamp(26px,3.2vw,38px);margin-bottom:12px">The limits, up front.</h2>
<p style="max-width:760px;color:var(--ink-dim);font-size:16px">A tool that claims to catch everything is a tool you cannot trust on anything. This one answers a single narrow question, and these are the questions it does not answer.</p>
<ul class="cannot">
<li><b>Whether the fix is correct</b>A perfectly correct fix with no test is <code class="mono">NO_GATE</code>. A subtly wrong fix with a test that pins the wrong behaviour is <code class="mono">GATE_HOLDS</code>. It measures whether a change is observable, never whether it is right.</li>
<li><b>Whether the change covers every case</b><code class="mono">GATE_HOLDS</code> means the tests notice this change. It says nothing about the case the author never considered — We have a worked example of our own: a SollanSystems/loop-engineer pull request that left SQLite sidecar files behind on a crash-recovered store. We refuted it by hand — and when we later ran this check against it, the verdict was <code class="mono">GATE_HOLDS</code>. The tests did gate the change. The change was still incomplete. Finding that needs a person, or the deeper adversarial pass, not this.</li>
<li><b>Anything about code the runner cannot reach</b>Frontend assets under a Go test runner, dependency manifests, generated files. These are reported as unreachable rather than silently counted.</li>
<li><b>Whether the pull request should be merged</b>It produces one piece of evidence for a human decision. It is non-blocking by default for exactly that reason.</li>
</ul>
</section>
<div class="divider"></div>
<!-- ================= OPEN SOURCE ================= -->
<section class="wrap proof" id="open">
<div class="sec-tag" style="justify-content:center">Open source</div>
<p class="proof-quote">Everything it says, it established by running something.</p>
<div class="stats">
<div class="stat"><span class="dim-line"></span><div class="num">0</div><div class="cap">dependencies — pure stdlib</div></div>
<div class="stat amber"><span class="dim-line"></span><div class="num">513</div><div class="cap">unit tests, no network needed</div></div>
<div class="stat"><span class="dim-line"></span><div class="num">5</div><div class="cap">languages supported</div></div>
</div>
<p class="proof-sub">MIT licensed. Runs entirely on your runner — no telemetry and no analytics, and nothing is sent anywhere. It touches the network only for git and, unless you set <code class="mono">install-deps: false</code>, to install your project’s own declared test dependencies. Secrets are stripped from the environment of every subprocess that runs your repository’s code, so a pull request cannot read your workflow token out of a test.</p>
<div class="hero-cta" style="justify-content:center;margin-top:30px">
<a href="https://github.com/earfman/coretexa-verify" target="_blank" rel="noopener" class="btn btn-primary btn-lg">★ Star on GitHub</a>
<a href="https://github.com/earfman/coretexa-verify#readme" target="_blank" rel="noopener" class="btn btn-ghost btn-lg">Read the docs</a>
</div>
</section>
<div class="divider"></div>
<!-- ================= FINAL ================= -->
<section class="final wrap">
<h2>Find out before you merge.</h2>
<p>One file in <code class="mono" style="color:var(--amber)">.github/workflows</code>. It is free and MIT, it runs on your own runner — usually two extra test runs per pull request, and Actions is free on public repos — and it tells you the one thing a green check never will.</p>
<div class="final-cta">
<a href="https://github.com/marketplace/actions/coretexa-verify" target="_blank" rel="noopener" class="btn btn-primary btn-lg">Get it on the Marketplace</a>
<a href="/proof.html" class="btn btn-ghost btn-lg">See what it caught</a>
</div>
<p class="honest">early, solo, and MIT — issues and pull requests welcome</p>
<p style="font-size:15px;color:var(--ink);max-width:600px;margin:34px auto 0;padding-top:26px;border-top:1px solid var(--hair);line-height:1.6">
<b style="color:var(--white)">Want this run across pull requests you have already merged?</b><br>
We do that by hand — the check first, a person reading every finding, then a short write-up of the ones worth acting on.
<a href="mailto:hello@coretexa.dev" style="color:var(--cyan);white-space:nowrap">Ask →</a>
</p>
</section>
<footer>
<div class="foot-in">
<span><b style="color:var(--white);letter-spacing:.12em">CORETEXA</b> <span class="dot">·</span> coretexa.dev</span>
<span>MIT <span class="dot">·</span> 2026 <span class="dot">·</span> a test that passes without the fix was never a gate</span>
<a href="https://github.com/earfman/coretexa-verify" target="_blank" rel="noopener">GitHub →</a>
</div>
</footer>
<script>
(function(){
"use strict";
var nav = document.getElementById('nav'), tog = document.getElementById('navToggle');
if(tog){ tog.addEventListener('click', function(){ nav.classList.toggle('open'); }); }
Array.prototype.forEach.call(document.querySelectorAll('.nav-links a'), function(a){
a.addEventListener('click', function(){ nav.classList.remove('open'); });
});
if('IntersectionObserver' in window){
var io = new IntersectionObserver(function(entries){
entries.forEach(function(e){ if(e.isIntersecting){ e.target.classList.add('in'); io.unobserve(e.target); } });
},{threshold:.14, rootMargin:'0px 0px -40px 0px'});
Array.prototype.forEach.call(document.querySelectorAll('.reveal'), function(el){ io.observe(el); });
} else {
Array.prototype.forEach.call(document.querySelectorAll('.reveal'), function(el){ el.classList.add('in'); });
}
})();
</script>
</body>
</html>