# TesterArmy e2e and Independent Validation With Katalon True Platform

*TesterArmy built a strong runner for agentic tests; at enterprise scale the harder job is proving the result, and that takes independent validation.*

> Katalon True Platform's lead product manager on TesterArmy's open-source e2e AI testing framework: what the team got right, why enterprise QA in regulated industries like banking (BFSI) and healthcare needs independent validation of AI-generated tests, and how e2e can run as an execution lane under True Platform's versioned test cases, requirements traceability, and audit trail.

Published: 2026-10-06 · Reading time: 12 min · Tags: independent-validation, ai-test-verification, qa, ai-testing, agentic-testing, e2e, testerarmy, katalon, katalon-true-platform, enterprise-qa, test-management, requirements-traceability, audit-trail, regulated-industries, bfsi, banking, healthcare, compliance, junit, test-data, release-readiness
Canonical URL: https://huytieu.com/blog/e2e-and-katalon-true/
Author: Huy Tieu (huytieu.com)

---

<style>
:root{--ef-ground:#ffffff;--ef-deep:#f1f3f7;--ef-ink:#111827;--ef-soft:#334155;--ef-muted:#64748b;--ef-quiet:#94a3b8;--ef-line:#e6e8ee;--ef-strong:#cbd5e1;--ef-accent:#c15f3c;--ef-node:#d97757;--ef-sans:Inter,ui-sans-serif,system-ui,sans-serif;--ef-mono:"JetBrains Mono",ui-monospace,"SF Mono",Menlo,monospace}
:root[data-theme="dark"]{--ef-ground:#171b22;--ef-deep:#11151b;--ef-ink:#f1f5f9;--ef-soft:#cbd5e1;--ef-muted:#8b95a5;--ef-quiet:#5b6472;--ef-line:#262c36;--ef-strong:#3a4250;--ef-accent:#e0885f;--ef-node:#e0885f}
.ef{margin:40px 0;padding:22px 22px 16px;border:1px solid var(--ef-line);background:var(--ef-ground);color:var(--ef-ink);box-shadow:0 1px 2px rgba(16,24,40,.04)}
.ef figcaption{margin-top:18px;padding-top:12px;border-top:1px solid var(--ef-line);font:500 9px/1.6 var(--ef-mono);letter-spacing:.1em;text-transform:uppercase;color:var(--ef-muted)}
.ef__k{font:500 9px/1 var(--ef-mono);letter-spacing:.12em;text-transform:uppercase;color:var(--ef-quiet);margin-bottom:14px}
.ef svg{width:100%;height:auto;display:block;overflow:visible}
.ef svg text{font-family:var(--ef-mono)}
/* F1 readers */
.ef-read{display:grid;grid-template-columns:150px 1fr;gap:0 18px;align-items:stretch}
.ef-pass{display:flex;flex-direction:column;justify-content:center;align-items:flex-start;border:1px solid var(--ef-ink);padding:14px}
.ef-pass b{font:600 18px/1 var(--ef-mono);letter-spacing:.04em}
.ef-pass small{font:400 10px/1.4 var(--ef-mono);color:var(--ef-muted);margin-top:8px}
.ef-rows{display:grid;gap:8px}
.ef-row{position:relative;display:grid;grid-template-columns:100px 1fr 132px;gap:12px;align-items:center;padding:9px 12px;border:1px solid var(--ef-line)}
.ef-row__who{font:500 9px/1.3 var(--ef-mono);letter-spacing:.1em;text-transform:uppercase;color:var(--ef-quiet)}
.ef-row__q{font:400 13px/1.4 var(--ef-sans);color:var(--ef-soft)}
.ef-row__s{font:500 9px/1.3 var(--ef-mono);letter-spacing:.08em;text-transform:uppercase;text-align:right;color:var(--ef-ink)}
.ef-row--gap{border-style:dashed}
.ef-row--gap .ef-row__s{color:var(--ef-accent)}
.ef-row::before{content:"";position:absolute;left:-19px;top:50%;width:18px;height:1px;background:var(--ef-strong)}
.ef-row i{position:absolute;left:-19px;top:calc(50% - 3px);width:6px;height:6px;border-radius:50%;background:var(--ef-ink);opacity:0;animation:ef-ping 6s ease-in-out infinite}
.ef-row--gap i{background:var(--ef-node)}
.ef-row:nth-child(2) i{animation-delay:1.5s}.ef-row:nth-child(3) i{animation-delay:3s}.ef-row:nth-child(4) i{animation-delay:4.5s}
@keyframes ef-ping{0%{opacity:0;transform:translateX(0)}5%{opacity:1}20%{opacity:1;transform:translateX(16px)}26%,100%{opacity:0;transform:translateX(16px)}}
/* F2 replay grid */
.ef-grid{display:grid;grid-template-columns:minmax(150px,1.3fr) repeat(3,1fr);border-top:1px solid var(--ef-line);border-left:1px solid var(--ef-line);position:relative}
.ef-grid>div{border-right:1px solid var(--ef-line);border-bottom:1px solid var(--ef-line);padding:9px 10px;min-height:38px;display:flex;align-items:center}
.ef-h{font:500 9px/1.3 var(--ef-mono);letter-spacing:.1em;text-transform:uppercase;color:var(--ef-quiet)}
.ef-step{font:400 11px/1.35 var(--ef-mono);color:var(--ef-soft)}
.ef-c{justify-content:center}
.ef-c span{font:500 9px/1 var(--ef-mono);letter-spacing:.1em;text-transform:uppercase;padding:5px 7px;border:1px solid var(--ef-strong);color:var(--ef-muted)}
.ef-c .m{background:var(--ef-ink);border-color:var(--ef-ink);color:var(--ef-ground)}
.ef-c .ma{background:var(--ef-node);border-color:var(--ef-node);color:#fff}
.ef-c .r{border-color:var(--ef-ink);color:var(--ef-ink)}
.ef-c .x{border-style:dashed;color:var(--ef-ink)}
.ef-c .n{border:0;color:var(--ef-quiet)}
.ef-col{position:absolute;top:0;bottom:0;width:calc((100% - (100% * 1.3 / 4.3)) / 3);left:calc(100% * 1.3 / 4.3);background:var(--ef-ink);opacity:.045;pointer-events:none;animation:ef-sweep 7.5s steps(1) infinite}
@keyframes ef-sweep{0%{transform:translateX(0)}33.3%{transform:translateX(100%)}66.6%{transform:translateX(200%)}}
.ef-keyrow{display:flex;flex-wrap:wrap;gap:14px;margin-top:12px;font:400 9px/1 var(--ef-mono);letter-spacing:.08em;text-transform:uppercase;color:var(--ef-quiet)}
.ef-keyrow span{display:flex;align-items:center;gap:6px}
.ef-keyrow i{display:inline-block;width:14px;height:9px;border:1px solid var(--ef-strong)}
.ef-keyrow i.m{background:var(--ef-ink);border-color:var(--ef-ink)}.ef-keyrow i.ma{background:var(--ef-node);border-color:var(--ef-node)}.ef-keyrow i.r{border-color:var(--ef-ink)}.ef-keyrow i.x{border-style:dashed;border-color:var(--ef-ink)}
/* F3 loop vs relay */
.ef-two{display:grid;grid-template-columns:1fr 1.35fr;gap:22px}
.ef-pane{border:1px solid var(--ef-line);padding:14px}
.ef-orbit{position:relative;width:210px;height:210px;margin:6px auto 4px}
.ef-orbit__ring{position:absolute;inset:22px;border:1px solid var(--ef-strong);border-radius:50%}
.ef-orbit__spin{position:absolute;inset:22px;animation:ef-spin 6s linear infinite}
.ef-orbit__spin i{position:absolute;top:-4px;left:calc(50% - 4px);width:8px;height:8px;border-radius:50%;background:var(--ef-ink)}
@keyframes ef-spin{to{transform:rotate(360deg)}}
.ef-orbit__c{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;font:520 15px/1.1 var(--ef-sans)}
.ef-orbit__c small{font:500 8px/1.4 var(--ef-mono);letter-spacing:.1em;text-transform:uppercase;color:var(--ef-quiet);margin-top:4px}
.ef-orbit__l{position:absolute;font:500 8px/1.2 var(--ef-mono);letter-spacing:.08em;text-transform:uppercase;color:var(--ef-muted);white-space:nowrap;transform:translate(-50%,-50%);background:var(--ef-ground);padding:2px 3px}
.ef-relay{display:grid;gap:10px}
.ef-hand{display:grid;grid-template-columns:96px 1fr 62px;gap:10px;align-items:center;position:relative}
.ef-hand__who{font:500 9px/1.3 var(--ef-mono);letter-spacing:.1em;text-transform:uppercase;color:var(--ef-quiet)}
.ef-hand__act{font:400 12px/1.35 var(--ef-sans);color:var(--ef-soft);border:1px solid var(--ef-line);padding:7px 9px;position:relative;overflow:hidden}
.ef-hand__act i{position:absolute;left:0;bottom:0;height:2px;width:0;background:var(--ef-ink);animation:ef-fill 8s ease-in-out infinite}
.ef-hand:nth-child(2) .ef-hand__act i{animation-delay:2s}.ef-hand:nth-child(3) .ef-hand__act i{animation-delay:4s}.ef-hand:nth-child(4) .ef-hand__act i{animation-delay:6s}
@keyframes ef-fill{0%{width:0;opacity:1}18%{width:100%;opacity:1}25%,100%{width:100%;opacity:0}}
.ef-store{font:500 9px/1 var(--ef-mono);letter-spacing:.08em;text-transform:uppercase;text-align:center;padding:6px 0;border:1px solid var(--ef-ink)}
.ef-store--q{border:1px dashed var(--ef-accent);color:var(--ef-accent)}
/* F4 / F5 svg */
.ef-svg .lbl{font-size:10px;fill:var(--ef-soft)}
.ef-svg .tag{font-size:8px;letter-spacing:.1em;fill:var(--ef-quiet);text-transform:uppercase}
.ef-svg .node{fill:var(--ef-ground);stroke:var(--ef-ink);stroke-width:1}
.ef-svg .node--q{stroke-dasharray:3 3;stroke:var(--ef-strong)}
.ef-svg .edge{stroke:var(--ef-strong);stroke-width:1;fill:none}
.ef-svg .edge--a{stroke:var(--ef-accent);stroke-width:1.5;stroke-dasharray:5 4;animation:ef-dash 1.6s linear infinite}
.ef-svg .edge--d{stroke-dasharray:3 4}
.ef-svg .lbl--a{fill:var(--ef-accent);font-weight:600}
.ef-svg .box{fill:var(--ef-ground);stroke:var(--ef-line)}
.ef-svg .box--a{stroke:var(--ef-accent)}
.ef-svg .dot{fill:var(--ef-node)}
@keyframes ef-dash{to{stroke-dashoffset:-18}}
.ef-svg .sig{fill:var(--ef-node);offset-rotate:0deg;animation:ef-move 4.5s ease-in-out infinite}
@keyframes ef-move{0%{offset-distance:0%;opacity:0}8%{opacity:1}70%{offset-distance:100%;opacity:1}85%,100%{offset-distance:100%;opacity:0}}
/* F6 rail */
.ef-rail{display:grid;grid-template-columns:repeat(6,1fr);border:1px solid var(--ef-line);position:relative}
.ef-st{padding:12px 10px 14px;border-right:1px solid var(--ef-line);min-height:118px;display:flex;flex-direction:column;position:relative}
.ef-st:last-child{border-right:0}
.ef-st>span{font:500 8px/1 var(--ef-mono);color:var(--ef-quiet)}
.ef-st>b{margin-top:auto;font:540 13px/1.25 var(--ef-sans);color:var(--ef-ink)}
.ef-st>small{margin-top:5px;font:400 9px/1.4 var(--ef-mono);color:var(--ef-muted);min-height:26px}
.ef-st>em{font:500 8px/1.45 var(--ef-mono);letter-spacing:.1em;text-transform:uppercase;font-style:normal;margin-top:9px;color:var(--ef-quiet)}
.ef-st--b{background:repeating-linear-gradient(135deg,transparent 0 6px,var(--ef-deep) 6px 7px)}
.ef-st--b>em{color:var(--ef-soft)}
.ef-st--a{box-shadow:inset 0 2px var(--ef-accent)}
.ef-st--a>em,.ef-st--a>b{color:var(--ef-accent)}
.ef-rail__dot{position:absolute;top:-4px;left:0;width:7px;height:7px;border-radius:50%;background:var(--ef-ink);animation:ef-travel 7s ease-in-out infinite}
@keyframes ef-travel{0%{left:0;background:var(--ef-ink)}60%{left:calc(66.6% - 4px);background:var(--ef-ink)}70%,88%{left:calc(91.6% - 4px);background:var(--ef-node)}100%{left:calc(100% - 7px);background:var(--ef-node)}}
/* screenshots */
.ef-shot{margin:30px 0}
.ef-shot img{width:100%;display:block;border:1px solid var(--ef-line)}
.ef-shot figcaption{margin-top:8px;font:400 10px/1.5 var(--ef-mono);letter-spacing:.06em;text-transform:uppercase;color:var(--ef-muted)}
/* tweets */
.ef-tw{margin:28px auto;max-width:440px}
.ef-tw img{width:100%;display:block;border:1px solid var(--ef-line)}
.ef-tw figcaption{margin-top:8px;font:400 10px/1.5 var(--ef-mono);letter-spacing:.06em;text-transform:uppercase;color:var(--ef-muted);text-align:center}
.ef-tw2{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin:28px 0;align-items:start}
.ef-tw2 .ef-tw{margin:0;max-width:none}
@media (max-width:700px){
 .ef{padding:16px 14px 12px}
 .ef-read,.ef-two,.ef-tw2{grid-template-columns:1fr}
 .ef-pass{margin-bottom:12px}
 .ef-row{grid-template-columns:1fr;gap:4px}.ef-row__s{text-align:left}.ef-row::before,.ef-row i{display:none}
 .ef-grid{grid-template-columns:118px repeat(3,1fr)}.ef-grid>div{padding:7px 5px}.ef-step{font-size:10px;word-break:break-all}.ef-c span{padding:4px 4px;font-size:8px}
 .ef-grid>.ef-col{display:none}
 .ef-rail{grid-template-columns:1fr 1fr}.ef-st{border-bottom:1px solid var(--ef-line)}.ef-rail__dot{display:none}
 .ef-hand{grid-template-columns:80px 1fr 54px}
}
/* independent validation */
.ef-iv{display:grid;grid-template-columns:118px 1fr 1.5fr;gap:6px 12px;align-items:stretch}
.ef-iv__h{font:500 9px/1 var(--ef-mono);letter-spacing:.12em;text-transform:uppercase;color:var(--ef-quiet);padding-bottom:4px}
.ef-iv__c{font:520 13px/1.3 var(--ef-sans);color:var(--ef-ink);display:flex;align-items:center;gap:8px}
.ef-iv__c span{font:500 8px/1 var(--ef-mono);color:var(--ef-quiet)}
.ef-iv__one{grid-column:2;grid-row:2/span 5;border:1px dashed var(--ef-strong);padding:14px;display:flex;flex-direction:column;justify-content:center;align-items:center;text-align:center;position:relative;gap:6px}
.ef-iv__one b{font:540 15px/1.2 var(--ef-sans)}
.ef-iv__one small{font:400 11px/1.45 var(--ef-mono);color:var(--ef-muted);max-width:180px}
.ef-iv__one em{font:500 9px/1.4 var(--ef-mono);letter-spacing:.08em;text-transform:uppercase;font-style:normal;color:var(--ef-muted);max-width:170px}
.ef-iv__loop{width:46px;height:46px;border:1px solid var(--ef-strong);border-radius:50%;position:relative;margin:6px 0;animation:ef-spin 3s linear infinite}
.ef-iv__loop::after{content:"";position:absolute;top:-4px;left:calc(50% - 4px);width:7px;height:7px;border-radius:50%;background:var(--ef-ink)}
.ef-iv__o{grid-column:3;border:1px solid var(--ef-line);padding:9px 12px 9px 26px;display:grid;grid-template-columns:1fr auto;column-gap:10px;align-items:center;position:relative}
.ef-iv__o b{font:520 13px/1.3 var(--ef-sans);color:var(--ef-ink)}
.ef-iv__o small{grid-column:1;font:400 11px/1.4 var(--ef-mono);color:var(--ef-muted)}
.ef-iv__o u{grid-column:2;grid-row:1/span 2;text-decoration:none;font:500 9px/1 var(--ef-mono);letter-spacing:.1em;text-transform:uppercase;padding:5px 7px;border:1px solid var(--ef-ink);color:var(--ef-ink)}
.ef-iv__o u.e{border-style:dashed;color:var(--ef-muted);border-color:var(--ef-strong)}
.ef-iv__o i{position:absolute;left:10px;top:calc(50% - 4px);width:7px;height:7px;border-radius:50%;background:var(--ef-strong);animation:ef-hop 7.5s ease-in-out infinite}
.ef-iv__o:nth-of-type(2) i{animation-delay:0s}
.ef-iv>.ef-iv__o:nth-child(8) i{animation-delay:1.5s}.ef-iv>.ef-iv__o:nth-child(10) i{animation-delay:3s}.ef-iv>.ef-iv__o:nth-child(12) i{animation-delay:4.5s}.ef-iv>.ef-iv__o:nth-child(14) i{animation-delay:6s}
@keyframes ef-hop{0%,100%{background:var(--ef-strong);transform:scale(1)}6%,16%{background:var(--ef-node);transform:scale(1.35)}24%{background:var(--ef-strong);transform:scale(1)}}
.ef-iv__o--a{border-color:var(--ef-accent);box-shadow:inset 2px 0 var(--ef-accent)}
.ef-iv__o--a b{color:var(--ef-accent)}
@media (max-width:700px){.ef-iv{grid-template-columns:1fr}.ef-iv__h,.ef-iv__c{display:none}.ef-iv__one{grid-column:1;grid-row:auto}.ef-iv__o{grid-column:1}}
@media (prefers-reduced-motion:reduce){.ef *,.ef *::before{animation:none!important}.ef-row i,.ef-svg .sig{opacity:0}}
.tp{--tp-pri:#5959eb;--tp-pri-t:#dedefd;--tp-ink:#1a1a1a;--tp-body:#233145;--tp-mute:#6b7280;--tp-line:#e6e6e6;--tp-bg:#fff;--tp-nav:#f5f5f5;--tp-pass:#379b3c;--tp-pass-t:#e8f4e8;--tp-fail:#c03221;--tp-fail-t:#fbeae8;--tp-warn:#b36500;--tp-warn-t:#fff3e0;--tp-run:#5959eb;font-family:Inter,ui-sans-serif,system-ui,-apple-system,"Segoe UI",sans-serif;color:var(--tp-body);margin:36px 0}
.tp-win{border:1px solid var(--ef-line,#e6e8ee);border-radius:8px;overflow:hidden;background:var(--tp-bg);box-shadow:0 1px 2px rgba(16,24,40,.05),0 12px 32px -18px rgba(16,24,40,.25)}
.tp-bar{display:flex;align-items:center;gap:6px;padding:8px 12px;border-bottom:1px solid var(--tp-line);background:#fafafa}
.tp-bar i{width:9px;height:9px;border-radius:50%;background:#dcdcdc}
.tp-bar span{margin-left:10px;font:11px/1 ui-monospace,Menlo,monospace;color:#8a8f98;background:#fff;border:1px solid var(--tp-line);border-radius:4px;padding:4px 8px}
.tp-app{display:grid;grid-template-columns:150px 1fr;min-height:360px}
.tp-nav{background:var(--tp-nav);border-right:1px solid var(--tp-line);padding:10px 8px;font-size:12px}
.tp-nav .ws{border:1px solid var(--tp-line);background:#fff;border-radius:4px;padding:6px 8px;font-weight:600;color:var(--tp-ink);margin-bottom:10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tp-nav .tp-ni{display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:4px;color:var(--tp-body);text-decoration:none;line-height:16px}
.tp-nav .tp-ni b{width:12px;height:12px;border:1.5px solid currentColor;border-radius:3px;opacity:.6;flex:none}
.tp-nav .tp-ni.on{background:var(--tp-pri-t);color:var(--tp-pri);font-weight:600}
.tp-nav .tp-ni.sub{padding-left:28px;font-size:11.5px}
.tp-main{padding:14px 16px;min-width:0}
.tp-crumb{font-size:12px;color:var(--tp-mute);margin-bottom:6px}
.tp-crumb b{color:var(--tp-ink)}
.tp-h{display:flex;flex-wrap:wrap;align-items:center;gap:8px;font-size:12px;color:var(--tp-mute);margin-bottom:12px}
.tp-chip{display:inline-flex;align-items:center;gap:5px;font:600 11px/1 Inter,system-ui,sans-serif;letter-spacing:.02em;border-radius:4px;padding:5px 7px;border:1px solid transparent;text-transform:uppercase}
.tp-chip.f{color:var(--tp-fail);background:var(--tp-fail-t);border-color:#efc4be}
.tp-chip.p{color:var(--tp-pass);background:var(--tp-pass-t);border-color:#c5e3c6}
.tp-chip.r{color:var(--tp-run);background:var(--tp-pri-t);border-color:#c8c8fa}
.tp-chip.w{color:var(--tp-warn);background:var(--tp-warn-t);border-color:#f2d3a6}
.tp-chip.v{color:var(--tp-pri);background:#fff;border-color:var(--tp-pri);text-transform:none;position:relative}
.tp-chip.v::after{content:"";position:absolute;inset:-4px;border-radius:7px;border:2px solid var(--tp-pri);opacity:0;animation:tp-ring 3.2s ease-out infinite}
@keyframes tp-ring{0%,35%{opacity:0;transform:scale(.92)}50%{opacity:.45}80%,100%{opacity:0;transform:scale(1.08)}}
.tp-split{display:grid;grid-template-columns:1fr 1.45fr;gap:12px}
.tp-list{border:1px solid var(--tp-line);border-radius:4px;overflow:hidden}
.tp-list>div{display:flex;gap:8px;padding:8px 10px;border-top:1px solid var(--tp-line);font-size:12px;line-height:16px;color:var(--tp-ink)}
.tp-list>div:first-child{border-top:0;font:600 10px/1 Inter,sans-serif;letter-spacing:.06em;text-transform:uppercase;color:var(--tp-mute);background:#fafafa}
.tp-list>div.sel{background:var(--tp-pri-t)}
.tp-list small{display:block;color:var(--tp-mute);font-size:11px;margin-top:2px}
.tp-ico{width:14px;height:14px;flex:none;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;color:#fff;font:700 9px/1 system-ui;margin-top:1px}
.tp-ico.p{background:var(--tp-pass)}.tp-ico.f{background:var(--tp-fail)}
.tp-drawer{border:1px solid var(--tp-line);border-radius:4px;padding:12px;min-width:0}
.tp-drawer h4{margin:0 0 4px;font:600 13px/18px Inter,sans-serif;color:var(--tp-ink)}
.tp-drawer .t{font-size:12px;line-height:16px;color:var(--tp-body);margin-bottom:8px}
.tp-tabs{display:flex;gap:16px;border-bottom:1px solid var(--tp-line);margin:10px 0;font:600 11px/1 Inter,sans-serif;letter-spacing:.04em}
.tp-tabs span{padding:0 0 8px;color:var(--tp-mute)}
.tp-tabs span.on{color:var(--tp-pri);box-shadow:inset 0 -2px var(--tp-pri)}
.tp-steps{display:grid;grid-template-columns:1.25fr 1fr;gap:10px}
.tp-step{display:flex;gap:7px;align-items:flex-start;padding:6px 7px;border-radius:4px;font-size:11.5px;line-height:15px;color:var(--tp-ink);opacity:0;animation:tp-in 9s ease-out infinite}
.tp-step small{display:block;color:var(--tp-mute);font-size:10.5px}
.tp-step:nth-child(1){animation-delay:0s}.tp-step:nth-child(2){animation-delay:.6s}.tp-step:nth-child(3){animation-delay:1.2s}.tp-step:nth-child(4){animation-delay:1.8s}.tp-step:nth-child(5){animation-delay:2.4s}
.tp-step.x{background:var(--tp-fail-t)}
@keyframes tp-in{0%{opacity:0;transform:translateY(4px)}5%,92%{opacity:1;transform:none}100%{opacity:0}}
.tp-shot{border:1px solid var(--tp-line);border-radius:4px;background:#fbfbfd;padding:10px;display:grid;grid-template-columns:1fr;gap:8px;align-content:start}
.tp-shot .l{display:grid;gap:5px;align-content:center}
.tp-shot .l i{display:block;height:7px;border:1px solid var(--tp-line);border-radius:3px;background:#fff}
.tp-shot .l i:first-child{width:40%;border:0;background:#d8d8de;height:6px}
.tp-shot .r{border-radius:4px;background:linear-gradient(135deg,#5959eb,#7a6ff0);min-height:70px;position:relative}
.tp-shot .r::after{content:"Ask Katalon Anything";position:absolute;left:8px;top:10px;font:600 10px/1.3 Inter,sans-serif;color:#fff;width:90px}
.tp-shot p{grid-column:1/-1;margin:2px 0 0;font:10px/1.4 ui-monospace,Menlo,monospace;color:var(--tp-mute)}
/* release readiness */
.tp-rr{padding:14px 16px}
.tp-rr .top{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;font-size:12px;color:var(--tp-mute)}
.tp-rr .top b{color:var(--tp-ink)}
.tp-btn{background:var(--tp-pri);color:#fff;border-radius:4px;padding:6px 10px;font:600 11px/1 Inter,sans-serif}
.tp-kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;margin-bottom:10px}
.tp-kpi{border:1px solid var(--tp-line);border-radius:4px;padding:9px 10px}
.tp-kpi span{font:600 9.5px/1 Inter,sans-serif;letter-spacing:.06em;text-transform:uppercase;color:var(--tp-mute)}
.tp-kpi b{display:block;font:600 20px/26px Inter,sans-serif;color:var(--tp-ink);margin-top:4px;letter-spacing:-.01em}
.tp-kpi small{font-size:10.5px;color:var(--tp-mute)}
.tp-kpi.hi{border-color:var(--tp-pri);box-shadow:inset 0 2px var(--tp-pri)}
.tp-kpi.hi small{color:var(--tp-pass);font-weight:600}
.tp-two{display:grid;grid-template-columns:1.35fr 1fr;gap:8px}
.tp-box{border:1px solid var(--tp-line);border-radius:4px;padding:9px 10px;font-size:11.5px}
.tp-box h5{margin:0 0 6px;font:600 11.5px/1 Inter,sans-serif;color:var(--tp-ink);display:flex;justify-content:space-between}
.tp-box h5 em{font-style:normal;font-weight:400;color:var(--tp-mute)}
.tp-row{display:grid;grid-template-columns:1fr auto 52px;gap:8px;align-items:center;padding:5px 0;border-top:1px solid #f0f0f0;color:var(--tp-ink)}
.tp-row:first-of-type{border-top:0}
.tp-row code{font:10.5px ui-monospace,Menlo,monospace;color:var(--tp-mute);background:none;padding:0}
.tp-chip.r.live{animation:tp-blink 1.6s ease-in-out infinite}
@keyframes tp-blink{50%{opacity:.45}}
.tp-sign{display:grid;gap:6px;margin:4px 0 8px}
.tp-sign div{display:flex;align-items:center;gap:7px;color:var(--tp-ink)}
.tp-sign div em{margin-left:auto;font:10.5px ui-monospace,Menlo,monospace;font-style:normal;color:var(--tp-mute)}
.tp-sign .pend em{color:var(--tp-pri)}
.tp-o{width:12px;height:12px;border-radius:50%;border:2px solid var(--tp-pri);flex:none}
.tp-prog{height:5px;border-radius:3px;background:#ececf7;overflow:hidden}
.tp-prog i{display:block;height:100%;width:66.6%;background:var(--tp-pri);animation:tp-fill 4s ease-out infinite}
@keyframes tp-fill{0%{width:0}40%,100%{width:66.6%}}
.tp-audit{margin-top:6px;font-size:10.5px;color:var(--tp-mute)}
.tp-audit b{color:var(--tp-pri)}
.tp figcaption{margin-top:12px;font:400 10px/1.5 var(--ef-mono,ui-monospace,monospace);letter-spacing:.06em;text-transform:uppercase;color:var(--ef-muted,#64748b)}
@media (max-width:700px){.tp-app{grid-template-columns:1fr}.tp-nav{display:none}.tp-split,.tp-steps,.tp-two{grid-template-columns:1fr}.tp-list{display:none}.tp-kpis{grid-template-columns:1fr 1fr}}
@media (prefers-reduced-motion:reduce){.tp *,.tp *::after{animation:none!important}.tp-step{opacity:1}}
</style>

TesterArmy shipped something good last week. [e2e](https://github.com/tester-army/e2e) puts natural-language agent steps and exact assertions in the same TypeScript test, replays recorded actions without paying for the model again, and runs the same suite on web and mobile. That is a hard combination to get right, and the team got it right in an open-source 0.17 release.

I lead product for [Katalon True Platform](https://katalon.com/platform), so I read the launch with professional interest and a stake in the outcome. We work on a close cousin of the same problem, for banks, insurers, and healthcare companies whose suites run to thousands of cases across many teams. At that scale, running the test stops being the hard part. Proving the result is. The answer that keeps holding up is **independent validation**: whoever writes or runs a test should never be the only one grading it.

This is a public-docs read as of 6 October 2026. The e2e and True integration I sketch near the end is a proposal and does not exist yet.

<figure class="ef" role="img" aria-label="One passing test, four readers; only the engineer's question is answered by the run">
  <div class="ef__k">One green check, four readers</div>
  <div class="ef-read">
    <div class="ef-pass"><b>PASS</b><small>refund_partial_sub<br>run 4812 · 38s</small></div>
    <div class="ef-rows">
      <div class="ef-row"><i></i><div class="ef-row__who">Engineer</div><div class="ef-row__q">Does my code still work?</div><div class="ef-row__s">In the run</div></div>
      <div class="ef-row ef-row--gap"><i></i><div class="ef-row__who">QA reviewer</div><div class="ef-row__q">Were the negative cases covered?</div><div class="ef-row__s">Outside the run</div></div>
      <div class="ef-row ef-row--gap"><i></i><div class="ef-row__who">Product owner</div><div class="ef-row__q">Is this the behavior we agreed on?</div><div class="ef-row__s">Outside the run</div></div>
      <div class="ef-row ef-row--gap"><i></i><div class="ef-row__who">Release mgr</div><div class="ef-row__q">Did every variant run on this RC?</div><div class="ef-row__s">Outside the run</div></div>
    </div>
  </div>
  <figcaption>The run answers one of four questions. The other three need a record that lives somewhere else.</figcaption>
</figure>

## Launch week on X

TesterArmy co-founder Oskar ([@o_kwasniewski](https://x.com/o_kwasniewski)) [announced e2e on 1 October](https://x.com/o_kwasniewski/status/2105675143464763540). Five days later the post sat at 1.1M views, and two days after launch he [posted a star chart](https://x.com/o_kwasniewski/status/2106291635122213342) heading for 2k. Deserved.

<div class="ef-tw2">
<figure class="ef-tw"><a href="https://x.com/o_kwasniewski/status/2105675143464763540"><img src="/assets/e2e-true/oskar-launch@2x.jpg" alt="Oskar's launch post for e2e: fully open source, mix deterministic and agentic APIs, web and mobile, bring your own agent, run locally or in CI" loading="lazy"></a><figcaption>Launch post, 1 Oct 2026</figcaption></figure>
<figure class="ef-tw"><a href="https://x.com/o_kwasniewski/status/2106291635122213342"><img src="/assets/e2e-true/oskar-stars@2x.jpg" alt="Oskar's follow-up post with a GitHub star history chart for tester-army/e2e climbing to about 2k in early October" loading="lazy"></a><figcaption>Star history, 3 Oct 2026</figcaption></figure>
</div>

## What TesterArmy got right

e2e 0.17.0 mixes agent steps with locators, deterministic assertions, fixtures, hooks, retries, and CI support. It runs on Chromium, Firefox, WebKit, [physical mobile devices](https://github.com/tester-army/e2e/blob/e2e%400.17.0/docs/physical-devices.mdx), and [APIs](https://github.com/tester-army/e2e/blob/e2e%400.17.0/docs/api-testing.mdx), and emits JSON, JUnit, and Markdown. With its [assertion API](https://github.com/tester-army/e2e/blob/e2e%400.17.0/docs/reference/expect.mdx), an agent can find its way through the UI while an exact check decides pass or fail. That split is the right instinct.

The [replay cache](https://github.com/tester-army/e2e/blob/e2e%400.17.0/docs/cache.mdx) is the other strong call. Agent actions are recorded and replayed without model calls, while `agent.assert`, `agent.waitFor`, and `agent.extract` always run live. Strict mode fails a stale recording with `REPLAY_STALE` before the model can take the step over, which is the kind of loud failure a CI pipeline needs.

<figure class="ef" role="img" aria-label="Grid of four test steps across three runs showing which steps call the model, replay, or run as code">
  <div class="ef__k">The same test, three runs</div>
  <div class="ef-grid">
    <div class="ef-col"></div>
    <div class="ef-h">Step</div><div class="ef-h ef-c" style="text-align:center">Run 1<br>cold</div><div class="ef-h ef-c" style="text-align:center">Run 2<br>cached</div><div class="ef-h ef-c" style="text-align:center">Run 3<br>UI changed</div>
    <div class="ef-step">agent.act("log in")</div><div class="ef-c"><span class="m">Model</span></div><div class="ef-c"><span class="r">Replay</span></div><div class="ef-c"><span class="r">Replay</span></div>
    <div class="ef-step">agent.act("open order")</div><div class="ef-c"><span class="m">Model</span></div><div class="ef-c"><span class="r">Replay</span></div><div class="ef-c"><span class="x">Stale · stop</span></div>
    <div class="ef-step">agent.assert("prorated")</div><div class="ef-c"><span class="ma">Model</span></div><div class="ef-c"><span class="ma">Model</span></div><div class="ef-c"><span class="n">Not run</span></div>
    <div class="ef-step">expect(total)</div><div class="ef-c"><span>Code</span></div><div class="ef-c"><span>Code</span></div><div class="ef-c"><span class="n">Not run</span></div>
  </div>
  <div class="ef-keyrow"><span><i class="m"></i>Live model call</span><span><i class="ma"></i>Model call that replay never removes</span><span><i class="r"></i>Recorded replay</span><span><i class="x"></i>Strict reject</span><span><i></i>Deterministic code</span></div>
  <figcaption>Replay removes model calls from actions. An agent assertion calls the model on every run, and strict mode stops the run when a recording goes stale.</figcaption>
</figure>

One [public trial](https://github.com/FlorianRiquelme/friquelme.dev/pull/76) on a small Astro site (e2e 0.16.0) saw median runtime drop from 25.1s to 13.5s and model calls from 5 to 1 on cached runs, with both injected defects caught. A Playwright control caught both too and ran faster, and the author's verdict was "adapt". Early, encouraging, and clear about its limits.

## Independent validation

The best pushback in launch week came from [davert](https://x.com/davert), author of CodeceptJS and Codeception, now building Testomat.io. He [asked how anyone decides](https://x.com/davert/status/2105994078517399870) which checks belong in `agent.assert()` and which in `expect()`, and argued for [manual test cases as the blueprint](https://x.com/davert/status/2106497346116661468). The card in his post says it in a few words: a test written from code "repeats the bug"; a test written from approved intent "catches the bug".

<div class="ef-tw2">
<figure class="ef-tw"><a href="https://x.com/davert/status/2105994078517399870"><img src="/assets/e2e-true/davert-assert@2x.jpg" alt="davert asking how an agent should know which checks are written as assert versus expect, with an e2e sample test" loading="lazy"></a><figcaption>Assert or expect, 2 Oct 2026</figcaption></figure>
<figure class="ef-tw"><a href="https://x.com/davert/status/2106497346116661468"><img src="/assets/e2e-true/davert-manual-first@2x.jpg" alt="davert: use manual test cases as the blueprint for e2e tests; getting into thousands of slow e2e tests is another dead end" loading="lazy"></a><figcaption>Test cases first, 4 Oct 2026</figcaption></figure>
</div>

He is pointing at the oldest rule in quality engineering, and AI makes it urgent again. If the same agent reads the code, writes the test, runs it, and judges the result, a misunderstanding passes every step. Each check needs a different owner:

<figure class="ef" role="img" aria-label="Five checks in a test's life. In a single loop one agent owns all five. With independent validation each check has a different owner, and e2e covers test code, execution, and the verdict">
  <div class="ef__k">Who checks whom</div>
  <div class="ef-iv">
    <div class="ef-iv__h"></div><div class="ef-iv__h">Single loop</div><div class="ef-iv__h">Independent validation</div>
    <div class="ef-iv__c"><span>01</span>Intent</div>
    <div class="ef-iv__one"><b>One agent</b><small>reads the code, writes the test, runs it, grades it</small><i class="ef-iv__loop"></i><em>a misunderstanding passes every step</em></div>
    <div class="ef-iv__o"><i></i><b>QA + product</b><small>approve a versioned test case</small><u>True</u></div>
    <div class="ef-iv__c"><span>02</span>Test code</div>
    <div class="ef-iv__o"><i></i><b>Engineer or agent</b><small>written from the approved case</small><u class="e">e2e</u></div>
    <div class="ef-iv__c"><span>03</span>Execution</div>
    <div class="ef-iv__o"><i></i><b>Any runner</b><small>e2e, Studio, Playwright, Run with AI</small><u class="e">e2e</u></div>
    <div class="ef-iv__c"><span>04</span>Verdict</div>
    <div class="ef-iv__o"><i></i><b>Exact assertions</b><small>agent judgments flagged for review</small><u class="e">e2e</u></div>
    <div class="ef-iv__c"><span>05</span>Record + release</div>
    <div class="ef-iv__o ef-iv__o--a"><i></i><b>Independent record</b><small>reconciles runs; release manager signs off</small><u>True</u></div>
  </div>
  <figcaption>When one agent owns every step, nothing checks it. Independent validation gives each check a different owner, and e2e fits in as the code, the runner, and the exact verdict.</figcaption>
</figure>


e2e already covers the middle three well: the test code, the runner, and exact assertions that keep the model out of the verdict. The other two, approved intent and an independent record behind the release decision, live outside any single framework. That is the layer we build True Platform for.

<figure class="tp" role="img" aria-label="Recreated Katalon True Platform test result view: a failed result pinned to test case Version 2 with step-by-step evidence">
<div class="tp-win">
  <div class="tp-bar"><i></i><i></i><i></i><span>huy-tieu.katalon.io · Executions › History</span></div>
  <div class="tp-app">
    <nav class="tp-nav">
      <div class="ws">True Platform</div>
      <div class="tp-ni"><b></b>Home</div><div class="tp-ni"><b></b>Releases</div><div class="tp-ni"><b></b>Tests</div><div class="tp-ni on"><b></b>Executions</div><div class="tp-ni sub on" style="background:none">History</div><div class="tp-ni sub">Live Testing</div><div class="tp-ni"><b></b>Analytics</div>
    </nav>
    <div class="tp-main">
      <div class="tp-crumb">Executions › <b>Dogfood 2026-07-08 S03a granular</b></div>
      <div class="tp-h"><span class="tp-chip f">Failed</span> Manual · 7 passed · 4 failed</div>
      <div class="tp-split">
        <div class="tp-list">
          <div>Tests</div>
          <div><span class="tp-ico p">✓</span><span>GH-982 TC03 · Placeholder text never appears<small>02m37s</small></span></div>
          <div><span class="tp-ico p">✓</span><span>GH-982 TC04 · Acknowledgment before action<small>02m56s</small></span></div>
          <div class="sel"><span class="tp-ico f">✕</span><span>GH-982 TC05 · Status line copy is present-tense<small>02m42s</small></span></div>
          <div><span class="tp-ico p">✓</span><span>GH-982 TC06 · No raw tool names<small>02m49s</small></span></div>
        </div>
        <div class="tp-drawer">
          <h4>Test case result summary</h4>
          <div class="t">GH-982 TC05 · Status line copy is human present-tense with a leading action icon</div>
          <div class="tp-h" style="margin:0"><span class="tp-chip f">Failed</span><span>02m42s</span><span class="tp-chip v">Version 2</span></div>
          <div class="tp-tabs"><span class="on">LOGS</span><span>AI ANALYSIS</span></div>
          <div class="tp-steps">
            <div>
              <div class="tp-step"><span class="tp-ico p">✓</span><span>Navigate to the app<small>22:58:38</small></span></div>
              <div class="tp-step"><span class="tp-ico p">✓</span><span>Sign in if prompted<small>22:58:57</small></span></div>
              <div class="tp-step"><span class="tp-ico p">✓</span><span>Open Katalon AI chat<small>23:00:32</small></span></div>
              <div class="tp-step"><span class="tp-ico p">✓</span><span>Send the message<small>23:00:44</small></span></div>
              <div class="tp-step x"><span class="tp-ico f">✕</span><span>Read the status line<small>23:01:06</small></span></div>
            </div>
            <div class="tp-shot"><div class="l"><i></i><i></i><i></i><i></i></div><div class="r"></div><p>step screenshot · attached</p></div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
<figcaption>Recreated from Katalon True Platform (a July 2026 run on my own tenant): each result records the test-case version it ran against, with evidence per step.</figcaption>
</figure>

## What changes at enterprise scale

A small team can keep all five owners in one person's head. The engineer who writes the test also seeds the data, reads the CI failure, and decides whether to ship. In a bank or a hospital network those jobs belong to different people, often in different time zones, and each handoff needs a record that outlives the CI log.

<figure class="ef" role="img" aria-label="Left: one owner circling a six-step loop. Right: four roles handing off a refund test, only the first handoff stored in Git">
  <div class="ef-two">
    <div class="ef-pane">
      <div class="ef__k">Small team</div>
      <div class="ef-orbit">
        <div class="ef-orbit__ring"></div>
        <div class="ef-orbit__spin"><i></i></div>
        <div class="ef-orbit__c">1 owner<small>every step</small></div>
        <span class="ef-orbit__l" style="left:50%;top:10px">Write test</span>
        <span class="ef-orbit__l" style="left:91%;top:30%">Seed data</span>
        <span class="ef-orbit__l" style="left:91%;top:70%">Run in CI</span>
        <span class="ef-orbit__l" style="left:50%;top:200px">Read report</span>
        <span class="ef-orbit__l" style="left:9%;top:70%">Triage</span>
        <span class="ef-orbit__l" style="left:9%;top:30%">Release</span>
      </div>
    </div>
    <div class="ef-pane">
      <div class="ef__k">Ownership spreads</div>
      <div class="ef-relay">
        <div class="ef-hand"><div class="ef-hand__who">Engineer</div><div class="ef-hand__act">Writes the refund test<i></i></div><div class="ef-store">Git</div></div>
        <div class="ef-hand"><div class="ef-hand__who">QA reviewer</div><div class="ef-hand__act">Reviews intent and negative cases<i></i></div><div class="ef-store ef-store--q">?</div></div>
        <div class="ef-hand"><div class="ef-hand__who">Product owner</div><div class="ef-hand__act">Confirms partial-sub behavior<i></i></div><div class="ef-store ef-store--q">?</div></div>
        <div class="ef-hand"><div class="ef-hand__who">Release mgr</div><div class="ef-hand__act">Approves on evidence<i></i></div><div class="ef-store ef-store--q">?</div></div>
      </div>
    </div>
  </div>
  <figcaption>One owner closes the loop alone. Across four roles each handoff needs a record, and only the first one has a home in Git.</figcaption>
</figure>

Three things get harder. First, intent: thousands of existing manual cases carry domain knowledge nobody wrote down, so someone has to sort which are runnable and resolve ambiguous expectations before an agent turns them into code. Second, data: a refund test depends on payment method, subscription state, and permissions, and the result has to carry the dataset version and row so a reviewer can reproduce a failure.

<figure class="ef ef-svg" role="img" aria-label="Tree from a test case to a versioned dataset to three rows and three named tests; the result carries case, dataset version and row">
  <div class="ef__k">Where a result's identity comes from</div>
  <svg viewBox="0 0 720 300">
    <path class="edge" d="M90 150 C 150 150, 150 150, 210 150"/>
    <path class="edge" d="M290 150 C 330 150, 330 70, 370 70"/>
    <path class="edge" d="M290 150 L 370 150"/>
    <path class="edge" d="M290 150 C 330 150, 330 230, 370 230"/>
    <path class="edge" d="M530 70 L 545 70"/><path class="edge" d="M530 150 L 545 150"/><path class="edge" d="M530 230 L 545 230"/>
    <path id="ef-p5" class="edge" d="M90 150 C 150 150, 150 150, 210 150 L 290 150 L 370 150 L 545 150" style="stroke:none"/>
    <circle class="node" cx="70" cy="150" r="20"/><text class="lbl" x="70" y="154" text-anchor="middle">REF-12</text><text class="tag" x="70" y="190" text-anchor="middle">CASE</text>
    <rect class="box" x="210" y="134" width="80" height="32"/><text class="lbl" x="250" y="154" text-anchor="middle">refunds@v3</text><text class="tag" x="250" y="186" text-anchor="middle">REVIEWED DATASET</text>
    <circle class="node" cx="378" cy="70" r="6"/><text class="lbl" x="392" y="74">card_active_admin</text>
    <circle class="node" cx="378" cy="150" r="6" style="fill:var(--ef-node);stroke:var(--ef-node)"/><text class="lbl" x="392" y="154">card_partial_member</text>
    <circle class="node" cx="378" cy="230" r="6"/><text class="lbl" x="392" y="234">paypal_cancel_admin</text>
    <rect class="box" x="545" y="56" width="170" height="28"/><text class="lbl" x="555" y="74">test REF-12 [row 1]</text>
    <rect class="box box--a" x="545" y="136" width="170" height="28"/><text class="lbl lbl--a" x="555" y="154">REF-12 · v3 · row 2 · fail</text>
    <rect class="box" x="545" y="216" width="170" height="28"/><text class="lbl" x="555" y="234">test REF-12 [row 3]</text>
    <path class="edge edge--d" d="M630 164 L 630 266"/>
    <rect class="box" x="560" y="266" width="140" height="24" style="stroke-dasharray:3 3"/><text class="lbl" x="630" y="282" text-anchor="middle" style="font-size:9px;fill:var(--ef-quiet)">acct_8f2c91 · setup</text>
    <circle class="sig" r="4" style="offset-path:path('M90 150 C 150 150, 150 150, 210 150 L 290 150 L 370 150 L 545 150')"/>
  </svg>
  <figcaption>A failure is reproducible only if the result carries case, dataset version and row. The generated account ID changes every run and names nothing.</figcaption>
</figure>

Third, the meaning of a result across runs and frameworks: which tests were expected, which were selected and completed, which passed only after retry, and which failed because of the environment or the model provider. The [e2e Playwright migration guide](https://github.com/tester-army/e2e/blob/e2e%400.17.0/docs/migrate/playwright.mdx) is candid about its own gaps here too, including native HTML reporting and pixel-diff snapshots.

## e2e as a runner in the True flow

The natural fit is e2e as one more execution lane under a shared record. Engineers keep writing e2e tests in their repo and running them in CI. QA keeps reviewed, [versioned test cases](https://docs.katalon.com/katalon-platform/create-tests/manage-test-case-versions) and requirement links in True, next to Run with AI, Katalon Studio, Playwright, and manual runs. True's [Report Uploader](https://docs.katalon.com/katalon-platform/integrations/ci-cd/report-uploader-integration) already accepts JUnit, which e2e emits, and the [MCP server](https://docs.katalon.com/katalon-platform/testops-mcp-server) can link those cases to ALM-synced requirements.

<figure class="ef" role="img" aria-label="Six-stage pipeline from a fresh output directory to reconcile; three stages belong to an adapter that does not exist yet">
  <div class="ef__k">Proposed CI pipeline</div>
  <div class="ef-rail">
    <i class="ef-rail__dot"></i>
    <div class="ef-st"><span>01</span><b>Fresh output dir</b><small>no stale report survives</small><em>CI</em></div>
    <div class="ef-st"><span>02</span><b>e2e run</b><small>JSON + JUnit + artifacts</small><em>e2e · exists</em></div>
    <div class="ef-st ef-st--b"><span>03</span><b>Map + stage</b><small>case key, data row, commit</small><em>Adapter · to build</em></div>
    <div class="ef-st"><span>04</span><b>Upload</b><small>Report Uploader, JUnit</small><em>True · exists</em></div>
    <div class="ef-st ef-st--b"><span>05</span><b>Read back</b><small>what True actually stored</small><em>Adapter · to build</em></div>
    <div class="ef-st ef-st--b ef-st--a"><span>06</span><b>Reconcile</b><small>missing, flaky, partial</small><em>Adapter · to build</em></div>
  </div>
  <figcaption>Upload sits in the middle. The adapter's real job is the read-back and reconcile after it, where a missing or partial run becomes visible.</figcaption>
</figure>

The adapter's real job is preserving what the runner saw. In the e2e 0.17 [JUnit implementation](https://github.com/tester-army/e2e/blob/e2e%400.17.0/packages/e2e/src/report/junit.ts), a retry-pass becomes a passing testcase with a `flaky:` note, and an interrupted test becomes `<skipped>` with an `interrupted:` message. That is a sensible choice for a generic format. An independent record should keep flaky and interrupted as states of their own.

<figure class="ef ef-svg" role="img" aria-label="Five e2e outcomes mapped to three JUnit states; retry-pass and interrupted collapse into passing and skipped">
  <div class="ef__k">e2e outcome → JUnit state</div>
  <svg viewBox="0 0 720 280">
    <text class="tag" x="40" y="22">E2E 0.17 OUTCOME</text><text class="tag" x="470" y="22">JUNIT XML</text>
    <path class="edge" d="M200 55 C 330 55, 340 70, 470 70"/>
    <path class="edge edge--a" d="M200 105 C 330 105, 340 75, 470 75"/>
    <path class="edge" d="M200 155 C 330 155, 340 140, 470 140"/>
    <path class="edge edge--a" d="M200 205 C 330 205, 340 210, 470 210"/>
    <path class="edge edge--d" d="M200 255 C 330 255, 340 255, 470 255"/>
    <circle class="node" cx="40" cy="55" r="5"/><text class="lbl" x="56" y="59">passed, first try</text>
    <circle class="node" cx="40" cy="105" r="5" style="fill:var(--ef-node);stroke:var(--ef-node)"/><text class="lbl lbl--a" x="56" y="109">passed after retry</text>
    <circle class="node" cx="40" cy="155" r="5"/><text class="lbl" x="56" y="159">failed</text>
    <circle class="node" cx="40" cy="205" r="5" style="fill:var(--ef-node);stroke:var(--ef-node)"/><text class="lbl lbl--a" x="56" y="209">interrupted</text>
    <circle class="node node--q" cx="40" cy="255" r="5"/><text class="lbl" x="56" y="259">tags · attempts · cache hits</text>
    <rect class="box" x="470" y="56" width="150" height="32"/><text class="lbl" x="482" y="76">&lt;testcase/&gt;</text><text class="tag" x="630" y="76">+ note</text>
    <rect class="box" x="470" y="124" width="150" height="32"/><text class="lbl" x="482" y="144">&lt;failure/&gt; | &lt;error/&gt;</text>
    <rect class="box" x="470" y="194" width="150" height="32"/><text class="lbl" x="482" y="214">&lt;skipped/&gt;</text><text class="tag" x="630" y="214">+ message</text>
    <rect class="box" x="470" y="240" width="150" height="30" style="stroke-dasharray:3 3"/><text class="tag" x="482" y="259">DROPPED</text>
  </svg>
  <figcaption>Five outcomes land on three states. A retry-pass counts as a pass and an interrupted test counts as a skip; the difference survives only as free text.</figcaption>
</figure>

Completeness needs its own check too. The [CLI docs](https://github.com/tester-army/e2e/blob/e2e%400.17.0/docs/reference/cli.mdx) say a run that stops before its tests leaves the previous report files in place, and [reporter failures](https://github.com/tester-army/e2e/blob/e2e%400.17.0/docs/reference/reporters.mdx) never change the exit code. Reading back what was stored and reconciling it against what was expected to run is what turns an upload into validation.

## Regulated teams: BFSI and healthcare

In banking, insurance, and healthcare, independent validation is a requirement. Auditors and regulators ask, months after the release, which requirement a test proved, who approved the expected behavior, which test version ran on which build, and who signed off. With AI steps, they add which model made the judgment and what path the agent took.

<figure class="tp" role="img" aria-label="Recreated release readiness view from katalon.com: KPI tiles, test runs, and a release sign-off with two of three approvals and an audit trail attached">
<div class="tp-win">
  <div class="tp-bar"><i></i><i></i><i></i><span>testops.katalon.io/bfsi/release-readiness</span></div>
  <div class="tp-rr">
    <div class="top"><span>BFSI Core Banking › Releases › <b>Release 26.9 · readiness</b></span><span class="tp-btn">Share report</span></div>
    <div class="tp-kpis">
      <div class="tp-kpi"><span>Pass rate</span><b>98.4%</b><small>▲ 1.2 vs last run</small></div>
      <div class="tp-kpi"><span>Test cases</span><b>4,812</b><small>web · mobile · API</small></div>
      <div class="tp-kpi hi"><span>Requirements covered</span><b>312 / 312</b><small>Full traceability</small></div>
      <div class="tp-kpi"><span>Self-healed</span><b>37</b><small>locators auto-fixed</small></div>
    </div>
    <div class="tp-two">
      <div class="tp-box"><h5>Test runs <em>Last 24h</em></h5>
        <div class="tp-row"><span>Payments · Transfer limits regression</span><span class="tp-chip p">Passed</span><code>00:42:10</code></div>
        <div class="tp-row"><span>Onboarding · eKYC document flow</span><span class="tp-chip p">Passed</span><code>00:18:33</code></div>
        <div class="tp-row"><span>Core · Temenos T24 account opening</span><span class="tp-chip f">Failed</span><code>01:05:47</code></div>
        <div class="tp-row"><span>Mobile · iOS &amp; Android smoke</span><span class="tp-chip r live">Running</span><code>00:09:12</code></div>
      </div>
      <div class="tp-box"><h5>Release sign-off</h5>
        <div class="tp-sign">
          <div><span class="tp-ico p">✓</span>QA Lead approved<em>09:41</em></div>
          <div><span class="tp-ico p">✓</span>Compliance reviewed<em>10:12</em></div>
          <div class="pend"><span class="tp-o"></span>Release manager<em>Pending</em></div>
        </div>
        <div class="tp-prog"><i></i></div>
        <div class="tp-audit">2 of 3 approvals · <b>audit trail attached</b></div>
      </div>
    </div>
  </div>
</div>
<figcaption>Recreated from the release-readiness view on <a href="https://katalon.com/banking-financial-services-software-testing">Katalon for Financial Services</a> (illustrative data from Katalon's page): coverage, run status, and a sign-off trail in one place.</figcaption>
</figure>

Katalon builds True Platform for these teams. The [banking and financial services page](https://katalon.com/banking-financial-services-software-testing) describes every edit, run, and result logged for audit and regulatory examination, traceability from each test to a requirement or Jira ticket, and SSO, SCIM, and RBAC. The [healthcare page](https://katalon.com/healthcare-software-testing) frames the same controls around HIPAA, HITECH, and keeping PHI out of test environments, with [insurance](https://katalon.com/insurance-software-testing) and [public sector](https://katalon.com/government-and-public-sector-software-testing) versions alongside. [Katalon's security page](https://katalon.com/security) lists ISO/IEC 27001, 27017 and 42001 certification and a SOC 2 Type II attestation, with more in the [trust center](https://trust.katalon.com). A vendor certification covers the vendor's own controls. The validation process still belongs to the customer, and imported results only inherit an audit trail if the adapter keeps case links, attempts, and evidence intact.

## A pilot worth running

Take one important journey with several data variants, run it through e2e, record it in True, and break it on purpose:

| Injected condition | What must be true in True afterward |
|---|---|
| Real product defect | Failed, linked to the right case and row |
| Environment error | Distinguishable from a product failure |
| Pass only on retry | Marked flaky |
| Run interrupted | Incomplete, separate from skipped-by-choice |
| Test file renamed | Case link survives |
| Same report uploaded twice | No duplicates |
| Auditor starts from a requirement | Reaches the run, row, and evidence without an engineer |

Credit where it is due: TesterArmy made agentic testing feel like ordinary engineering, which is the hardest part to get right. The next step for the industry is making those results trustworthy to people who never saw the code. e2e as the runner and [Katalon True Platform](https://katalon.com/platform) as the independent record is a combination I would like to see proven.
