<?xml version="1.0"?><feed xmlns:media="http://search.yahoo.com/mrss/" xmlns:gr="http://www.google.com/schemas/reader/atom/" xmlns:idx="urn:atom-extension:indexing" xmlns="http://www.w3.org/2005/Atom" idx:index="no" gr:dir="ltr"><!--
Content-type: Preventing XSRF in IE.

--><generator uri="https://bazqux.com">BazQux Reader</generator><id>tag:google.com,2005:reader/feed/http://007unlicensedtotest.blogspot.com/feeds/posts/default</id><title>blogs</title><subtitle type="html">blogs</subtitle><link rel="self" href="https://bazqux.com/feed/d45a6ead98c5f8f9f99f?no_branding"></link><gr:continuation>4690104287876</gr:continuation><updated>2026-07-07T20:48:12Z</updated><entry gr:crawl-timestamp-msec="1783440000000"><id gr:original-id="https://www.bartvanherck.com/posts/2026/20260707/">tag:google.com,2005:reader/item/00000d9a00000015</id><title type="html">The Retrospective Nobody Believed In</title><published>2026-07-07T16:00:00Z</published><updated>2026-07-07T16:00:00Z</updated><link rel="alternate" href="https://www.bartvanherck.com/posts/2026/20260707/" type="text/html"></link><summary type="html">&lt;p&gt;Team Falcon holds a retrospective every two weeks. Every time, they run out of time. It is too short to get through everything that matters. The check-in gets skipped, the follow-up from last time gets forgotten. Every two weeks, the team shows up, goes through the motions, and moves on, as if attending the meeting is the same as improving.&lt;/p&gt;
&lt;p&gt;It is not.&lt;/p&gt;
&lt;h2 id=&quot;article-svniv03qER7W5bQ17EG4-fmY78w-an-empty-ceremony-is-worse-than-none&quot;&gt;An empty ceremony is worse than none&lt;/h2&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;

 &lt;img class=&quot;bqrUnknownImgSize&quot; src=&quot;https://www.bartvanherck.com/posts/2023/2023-10-31/wait.jpg&quot; alt style=&quot;width: 100px&quot;&gt;

&lt;/figure&gt;

The brain is a reward machine. Behavior that pays off gets repeated. Behavior that pays nothing back dies out slowly.&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Social media knows this well: every like, every reply is a small reward that pulls you back to the screen. A retrospective that consistently produces nothing works the same loop in reverse. You write down what went wrong. Nothing changes. Next sprint, you hit the same wall.&lt;/p&gt;
&lt;p&gt;The brain draws its quiet conclusion: this meeting is useless.&lt;/p&gt;
&lt;p&gt;People stop thinking about improvement. They fill in the sticky notes because it is expected, not because they believe anything will come of it. At that point you do not have a poorly run retrospective. You have a team that has lost trust in the process entirely.&lt;/p&gt;
&lt;p&gt;That is much harder to fix than a time problem.&lt;/p&gt;
&lt;h2 id=&quot;article-svniv03qER7W5bQ17EG4-fmY78w-four-observations-one-root-cause&quot;&gt;Four observations, one root cause&lt;/h2&gt;
&lt;p&gt;It is Owen who says it out loud first. One morning, without making it a confrontation, Owen brings four observations to the daily standup.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Time runs out.&lt;/strong&gt; Every standup, someone starts a technical discussion and nobody stops it. Fifteen minutes becomes thirty. Fix this by appointing a timekeeper, agreeing on a hard stop, and moving anything technical to a separate slot outside the standup.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;

 
 &lt;div style=&quot;width: 200px&quot;&gt;
 
&lt;svg fill=&quot;#000000&quot; viewbox=&quot;0 0 24 24&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;
 &lt;path d=&quot;M9,3 L9,21 L15,21 L15,3 L9,3 Z M8,3 L3.5,3 C2.67157288,3 2,3.67157288 2,4.5 L2,19.5 C2,20.3284271 2.67157288,21 3.5,21 L8,21 L8,3 Z M16,3 L16,21 L20.5,21 C21.3284271,21 22,20.3284271 22,19.5 L22,4.5 C22,3.67157288 21.3284271,3 20.5,3 L16,3 Z M1,4.5 C1,3.11928813 2.11928813,2 3.5,2 L20.5,2 C21.8807119,2 23,3.11928813 23,4.5 L23,19.5 C23,20.8807119 21.8807119,22 20.5,22 L3.5,22 C2.11928813,22 1,20.8807119 1,19.5 L1,4.5 Z M4,6 L6,6 C6.55228475,6 7,6.44771525 7,7 L7,8 C7,8.55228475 6.55228475,9 6,9 L4,9 C3.44771525,9 3,8.55228475 3,8 L3,7 C3,6.44771525 3.44771525,6 4,6 Z M4,10 L6,10 C6.55228475,10 7,10.4477153 7,11 L7,12 C7,12.5522847 6.55228475,13 6,13 L4,13 C3.44771525,13 3,12.5522847 3,12 L3,11 C3,10.4477153 3.44771525,10 4,10 Z M11,6 L13,6 C13.5522847,6 14,6.44771525 14,7 L14,8 C14,8.55228475 13.5522847,9 13,9 L11,9 C10.4477153,9 10,8.55228475 10,8 L10,7 C10,6.44771525 10.4477153,6 11,6 Z M18,6 L20,6 C20.5522847,6 21,6.44771525 21,7 L21,8 C21,8.55228475 20.5522847,9 20,9 L18,9 C17.4477153,9 17,8.55228475 17,8 L17,7 C17,6.44771525 17.4477153,6 18,6 Z M18,10 L20,10 C20.5522847,10 21,10.4477153 21,11 L21,12 C21,12.5522847 20.5522847,13 20,13 L18,13 C17.4477153,13 17,12.5522847 17,12 L17,11 C17,10.4477153 17.4477153,10 18,10 Z M18,14 L20,14 C20.5522847,14 21,14.4477153 21,15 L21,16 C21,16.5522847 20.5522847,17 20,17 L18,17 C17.4477153,17 17,16.5522847 17,16 L17,15 C17,14.4477153 17.4477153,14 18,14 Z M4,7 L4,8 L6,8 L6,7 L4,7 Z M4,11 L4,12 L6,12 L6,11 L4,11 Z M11,7 L11,8 L13,8 L13,7 L11,7 Z M18,7 L18,8 L20,8 L20,7 L18,7 Z M18,11 L18,12 L20,12 L20,11 L18,11 Z M18,15 L18,16 L20,16 L20,15 L18,15 Z M3.5,5 C3.22385763,5 3,4.77614237 3,4.5 C3,4.22385763 3.22385763,4 3.5,4 L6.5,4 C6.77614237,4 7,4.22385763 7,4.5 C7,4.77614237 6.77614237,5 6.5,5 L3.5,5 Z M10.5,5 C10.2238576,5 10,4.77614237 10,4.5 C10,4.22385763 10.2238576,4 10.5,4 L13.5,4 C13.7761424,4 14,4.22385763 14,4.5 C14,4.77614237 13.7761424,5 13.5,5 L10.5,5 Z M17.5,5 C17.2238576,5 17,4.77614237 17,4.5 C17,4.22385763 17.2238576,4 17.5,4 L20.5,4 C20.7761424,4 21,4.22385763 21,4.5 C21,4.77614237 20.7761424,5 20.5,5 L17.5,5 Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

 &lt;/div&gt;
 

&lt;/figure&gt;

&lt;strong&gt;Sprint stories get skipped.&lt;/strong&gt; The TODO column has stories waiting. Nobody picks them up. Instead, team members pull in new stories from the backlog, ones meant for a future sprint. The reason is simple: the sprint stories are configuration work, the backlog stories are coding work. The choice feels obvious. The sprint commitment quietly breaks down. The fix is not a WIP limit. It is a team agreement with one rule: no new stories enter the sprint while there are still stories waiting in TODO. Stick to the plan. If the configuration stories keep getting skipped, that is a separate conversation worth having about how those stories are written and who owns them.&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Complex stories are black boxes.&lt;/strong&gt; Nobody knows what is really inside them until someone picks one up and starts digging. Understanding grows as the work progresses, but the story description never changes. Fix this by making one person responsible for keeping the story content current. If the description is wrong, update it before moving on.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Remote meetings have bodies but not minds.&lt;/strong&gt; Cameras are on. Attention is somewhere else. Open questions to the group hang in the air because nobody expects to be called on directly. Fix this by asking specific people specific questions, rotating the role of notetaker each meeting, and keeping calls short enough that drifting has a cost.&lt;/p&gt;
&lt;p&gt;Four observations, together they point at a single root cause: the team runs without clear agreements, and nobody is keeping them. Not because people do not care. Because the agreements were never properly made or were made once and then quietly abandoned. The retrospective is exactly where these things should surface and get resolved.&lt;/p&gt;
&lt;h2 id=&quot;article-svniv03qER7W5bQ17EG4-fmY78w-cameras-do-not-create-presence&quot;&gt;Cameras do not create presence&lt;/h2&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;

 
 &lt;div style=&quot;width: 200px&quot;&gt;
 

&lt;svg version=&quot;1.1&quot; id=&quot;article-svniv03qER7W5bQ17EG4-fmY78w-Layer_1&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; viewbox=&quot;0 0 512 512&quot; xml:space=&quot;preserve&quot;&gt;
&lt;polygon style=&quot;fill: #5B5D6E&quot; points=&quot;315.494,408.453 195.777,408.453 187.226,485.413 324.045,485.413 &quot;&gt;&lt;/polygon&gt;
&lt;polygon style=&quot;fill: #464655&quot; points=&quot;319.457,444.125 315.492,408.453 195.776,408.453 191.814,444.125 &quot;&gt;&lt;/polygon&gt;
&lt;path style=&quot;fill: #707487&quot; d=&quot;M486.881,418.472H25.119c-9.446,0-17.102-7.656-17.102-17.102V93.528
	c0-9.446,7.656-17.102,17.102-17.102h461.762c9.446,0,17.102,7.656,17.102,17.102V401.37
	C503.983,410.814,496.326,418.472,486.881,418.472z&quot;&gt;&lt;/path&gt;
&lt;circle style=&quot;fill: #959CB5&quot; cx=&quot;256&quot; cy=&quot;67.875&quot; r=&quot;42.756&quot;&gt;&lt;/circle&gt;
&lt;rect x=&quot;42.221&quot; y=&quot;110.63&quot; style=&quot;fill: #FFDC64&quot; width=&quot;256&quot; height=&quot;273&quot;&gt;&lt;/rect&gt;
&lt;path style=&quot;fill: #D29B6E&quot; d=&quot;M235.755,354.716l-27.918-9.307c-6.984-2.328-11.694-8.863-11.694-16.225v-21.877h-51.307v21.878
	c0,7.361-4.71,13.897-11.694,16.225l-27.918,9.307c-6.984,2.328-11.694,8.863-11.694,16.225v13.326h153.921V370.94
	C247.449,363.579,242.739,357.044,235.755,354.716z&quot;&gt;&lt;/path&gt;
&lt;path style=&quot;fill: #959CB5&quot; d=&quot;M235.755,354.716l-27.918-9.307c-1.677-0.559-3.205-1.386-4.586-2.384
	c-7.844,9.446-19.527,15.589-32.762,15.589c-13.236,0-24.918-6.143-32.762-15.589c-1.381,0.997-2.908,1.826-4.586,2.384
	l-27.918,9.307c-6.984,2.328-11.694,8.863-11.694,16.225v13.327h153.921V370.94C247.449,363.579,242.739,357.044,235.755,354.716z&quot;&gt;&lt;/path&gt;
&lt;g&gt;
	&lt;ellipse style=&quot;fill: #694B4B&quot; cx=&quot;170.489&quot; cy=&quot;174.764&quot; rx=&quot;34.205&quot; ry=&quot;29.929&quot;&gt;&lt;/ellipse&gt;
	&lt;ellipse style=&quot;fill: #694B4B&quot; cx=&quot;170.489&quot; cy=&quot;234.622&quot; rx=&quot;68.409&quot; ry=&quot;64.134&quot;&gt;&lt;/ellipse&gt;
&lt;/g&gt;
&lt;path style=&quot;fill: #5A4146&quot; d=&quot;M187.018,172.452c-5.303-1.236-10.819-1.964-16.529-1.964c-37.781,0-68.409,28.714-68.409,64.134
	c0,30.414,22.607,55.826,52.91,62.418c0-11.005,0-27.379,0-51.729C154.99,208.267,172.826,185.087,187.018,172.452z&quot;&gt;&lt;/path&gt;
&lt;path style=&quot;fill: #F0C087&quot; d=&quot;M213.609,302.849l-27.823,13.912c-9.63,4.814-20.964,4.814-30.594,0l-27.823-13.912
	c-5.115-2.557-8.612-7.501-9.322-13.175l-5.194-41.55c-0.612-4.898,3.011-9.269,7.935-9.591
	c15.938-1.043,49.178-5.044,69.669-20.388c3.456-2.588,8.28-2.132,11.233,1.018l23.773,25.354c1.739,1.855,2.562,4.387,2.247,6.909
	l-4.781,38.247C222.222,295.347,218.723,300.292,213.609,302.849z&quot;&gt;&lt;/path&gt;
&lt;path style=&quot;fill: #E6AF78&quot; d=&quot;M225.465,244.517l-23.774-25.355c-2.974-3.171-7.815-3.569-11.298-0.968
	c-10.381,7.751-24.006,12.583-37.006,15.618v0.001c-12.713,2.967-24.825,4.214-32.68,4.726c-4.954,0.323-8.469,4.661-7.853,9.586
	l5.193,41.548c0.71,5.675,4.207,10.619,9.323,13.177l27.823,13.912c4.155,2.077,8.639,3.078,13.155,3.364L157.9,299.232
	c-2.968-5.936-4.514-12.481-4.514-19.118v-13.239c0-4.003,2.779-7.391,6.673-8.321c10.865-2.595,22.152-6.299,32.494-11.632
	l14.197,15.142c4.765,5.083,11.825,9.027,18.599,8.257l2.362-18.895C228.027,248.904,227.204,246.371,225.465,244.517z&quot;&gt;&lt;/path&gt;
&lt;rect x=&quot;298.756&quot; y=&quot;110.63&quot; style=&quot;fill: #7DF5A5&quot; width=&quot;171&quot; height=&quot;136&quot;&gt;&lt;/rect&gt;
&lt;path style=&quot;fill: #F0C087&quot; d=&quot;M422.62,220.432l-14.773-3.693c-3.807-0.951-6.477-4.372-6.477-8.296v-6.122
	c5.09-2.962,8.551-8.416,8.551-14.73v-42.756h-34.205c-9.445,0-17.102,7.656-17.102,17.102v25.653c0,6.314,3.461,11.767,8.551,14.73
	v6.122c0,3.924-2.67,7.344-6.478,8.296l-14.773,3.693c-7.614,1.904-12.954,8.745-12.954,16.591v10.426h102.614v-10.426
	C435.574,229.175,430.234,222.334,422.62,220.432z&quot;&gt;&lt;/path&gt;
&lt;path style=&quot;fill: #694B4B&quot; d=&quot;M409.921,144.835h-34.205c-9.446,0-17.102,7.656-17.102,17.102v17.102c0,0,25.653,0,51.307-8.551
	V144.835z&quot;&gt;&lt;/path&gt;
&lt;path style=&quot;fill: #707487&quot; d=&quot;M422.62,220.432l-11.837-2.959c-6.242,7.807-15.738,12.874-26.516,12.874
	c-10.778,0-20.274-5.068-26.516-12.874l-11.837,2.959c-7.614,1.904-12.954,8.745-12.954,16.591v10.426h102.614v-10.426
	C435.574,229.175,430.234,222.334,422.62,220.432z&quot;&gt;&lt;/path&gt;
&lt;rect x=&quot;298.756&quot; y=&quot;247.449&quot; style=&quot;fill: #00C3FF&quot; width=&quot;171&quot; height=&quot;136&quot;&gt;&lt;/rect&gt;
&lt;path style=&quot;fill: #F0C087&quot; d=&quot;M422.62,357.25l-14.773-3.693c-3.807-0.951-6.477-4.372-6.477-8.296v-6.122
	c5.09-2.962,8.551-8.416,8.551-14.73v-42.756h-34.205c-9.445,0-17.102,7.656-17.102,17.102v25.653c0,6.314,3.461,11.767,8.551,14.73
	v6.122c0,3.924-2.67,7.344-6.478,8.296l-14.773,3.693c-7.614,1.904-12.954,8.745-12.954,16.591v10.426h102.614v-10.426
	C435.574,365.993,430.234,359.152,422.62,357.25z&quot;&gt;&lt;/path&gt;
&lt;path style=&quot;fill: #694B4B&quot; d=&quot;M409.921,281.653h-34.205c-9.446,0-17.102,7.656-17.102,17.102v17.102c0,0,25.653,0,51.307-8.551
	V281.653z&quot;&gt;&lt;/path&gt;
&lt;path style=&quot;fill: #FFDC64&quot; d=&quot;M422.62,357.25l-11.837-2.959c-6.242,7.807-15.738,12.874-26.516,12.874
	c-10.778,0-20.274-5.068-26.516-12.874l-11.837,2.959c-7.614,1.904-12.954,8.745-12.954,16.591v10.426h102.614v-10.426
	C435.574,365.993,430.234,359.152,422.62,357.25z&quot;&gt;&lt;/path&gt;
&lt;path d=&quot;M486.881,68.409H306.759c0.002-0.179,0.014-0.355,0.014-0.534c0-27.995-22.777-50.772-50.772-50.772
	s-50.772,22.777-50.772,50.772c0,0.18,0.012,0.356,0.014,0.534H25.119C11.268,68.409,0,79.677,0,93.528V401.37
	c0,13.851,11.268,25.119,25.119,25.119h161.942l-6.547,52.376h-18.576c-4.427,0-8.017,3.589-8.017,8.017s3.589,8.017,8.017,8.017
	h188.125c4.427,0,8.017-3.589,8.017-8.017s-3.589-8.017-8.017-8.017h-18.576l-6.547-52.376h161.942
	c13.851,0,25.119-11.268,25.119-25.119V93.528C512,79.677,500.732,68.409,486.881,68.409z M461.762,118.647v120.785h-18.171v-2.409
	c0-11.548-7.824-21.568-19.027-24.369l-15.177-3.795v-2.482c5.363-4.722,8.551-11.569,8.551-18.787v-42.756
	c0-4.427-3.589-8.017-8.017-8.017h-34.205c-13.851,0-25.119,11.268-25.119,25.119v25.653c0,7.218,3.189,14.064,8.551,18.787v2.482
	l-15.178,3.795c-11.202,2.8-19.026,12.821-19.026,24.369v2.409h-18.171V118.647H461.762z M371.197,332.211
	c-2.859-1.664-4.566-4.581-4.566-7.802v-25.653c0-5.01,4.076-9.086,9.086-9.086h26.188v34.739c0,3.221-1.707,6.138-4.566,7.802
	c-2.467,1.436-3.985,4.075-3.985,6.929v12.798c0,3.678,2.503,6.885,6.072,7.777l21.25,5.312c4.052,1.013,6.883,4.638,6.883,8.815
	v2.408h-86.58v-2.409c0-4.177,2.829-7.802,6.882-8.815l21.251-5.311c3.569-0.893,6.072-4.099,6.072-7.777V339.14
	C375.182,336.285,373.664,333.647,371.197,332.211z M424.563,349.473l-15.177-3.795v-2.482c5.363-4.722,8.551-11.569,8.551-18.787
	v-42.756c0-4.427-3.589-8.017-8.017-8.017h-34.205c-13.851,0-25.119,11.268-25.119,25.119v25.653c0,7.218,3.189,14.064,8.551,18.787
	v2.482l-15.178,3.795c-11.202,2.801-19.026,12.821-19.026,24.369v2.409h-18.171V255.466h154.99v120.785h-18.171v-2.409
	C443.591,362.294,435.767,352.273,424.563,349.473z M371.197,195.393c-2.859-1.664-4.566-4.581-4.566-7.802v-25.653
	c0-5.01,4.076-9.086,9.086-9.086h26.188v34.739c0,3.221-1.707,6.138-4.566,7.802c-2.467,1.436-3.985,4.075-3.985,6.929v12.798
	c0,3.678,2.503,6.885,6.072,7.777l21.25,5.313c4.052,1.012,6.882,4.637,6.882,8.814v2.408h-86.58v-2.409
	c0-4.177,2.829-7.801,6.882-8.814l21.251-5.312c3.569-0.891,6.072-4.098,6.072-7.777v-12.798
	C375.182,199.466,373.664,196.828,371.197,195.393z M290.739,376.251h-35.273v-5.31c0-10.829-6.903-20.406-17.176-23.83
	l-27.918-9.307c-0.528-0.176-1.024-0.408-1.5-0.669c-0.096-0.088-0.186-0.18-0.288-0.263c-0.423-0.35-0.871-0.647-1.338-0.896
	c-1.911-1.688-3.087-4.125-3.087-6.792v-12.648l13.035-6.518l0,0c7.528-3.765,12.647-10.999,13.69-19.351l2.01-16.079
	c9.17-12.039,14.021-26.193,14.021-40.976c0-25.046-13.99-47.094-35.065-59.774c0.565-2.496,0.86-5.044,0.86-7.624
	c0-20.924-18.941-37.946-42.221-37.946s-42.221,17.022-42.221,37.946c0,2.577,0.29,5.129,0.856,7.628
	c-21.073,12.68-35.061,34.726-35.061,59.77c0,14.823,4.845,28.938,14.019,40.973l2.011,16.084
	c1.044,8.352,6.162,15.588,13.691,19.351l13.035,6.518v12.648c0,3.918-2.496,7.381-6.212,8.618l-27.918,9.307
	c-10.273,3.424-17.176,13.001-17.176,23.83v5.31H50.238V118.647h240.501V376.251z M101.545,376.251v-5.31
	c0-3.918,2.497-7.381,6.212-8.62l27.918-9.307c0.056-0.018,0.108-0.043,0.164-0.062c9.36,8.74,21.733,13.679,34.649,13.679
	c12.991,0,25.294-4.928,34.648-13.679c0.056,0.019,0.109,0.044,0.165,0.062l27.918,9.307c3.717,1.239,6.212,4.702,6.212,8.62v5.31
	H101.545z M144.301,166.213c0-12.083,11.748-21.912,26.188-21.912c14.44,0,26.188,9.83,26.188,21.912
	c0,0.186-0.021,0.369-0.027,0.555c-8.165-2.778-16.976-4.296-26.161-4.296c-9.186,0-17.998,1.518-26.163,4.296
	C144.32,166.583,144.301,166.399,144.301,166.213z M170.489,178.505c33.3,0,60.392,24.72,60.392,55.106
	c0,1.583-0.081,3.156-0.228,4.719l-28.663-30.569c-1.485-1.583-3.549-2.497-5.72-2.532c-2.177-0.027-4.263,0.812-5.798,2.347
	c-22.979,22.979-78.223,23.307-78.774,23.308c-0.518,0-1.03,0.057-1.532,0.155C111.646,201.843,138.133,178.505,170.489,178.505z
	 M120.74,246.583c16.635-1.028,52.262-5.215,74.812-22.247l24.236,25.848l-4.811,38.496c-0.378,3.022-2.229,5.638-4.952,7l0,0
	l-27.823,13.912c-7.335,3.666-16.09,3.665-23.424,0l-27.823-13.912c-2.724-1.362-4.575-3.978-4.952-7L120.74,246.583z
	 M152.852,324.509c5.573,2.56,11.602,3.857,17.637,3.857c6.035,0,12.064-1.297,17.637-3.857v4.676c0,5.02,1.498,9.76,4.112,13.753
	c-6.115,4.92-13.741,7.659-21.749,7.659c-7.962,0-15.622-2.746-21.747-7.662c2.613-3.992,4.11-8.732,4.11-13.75V324.509z
	 M256,33.136c19.155,0,34.739,15.584,34.739,34.739S275.155,102.614,256,102.614s-34.739-15.584-34.739-34.739
	S236.845,33.136,256,33.136z M315.328,478.864H196.672l6.547-52.376h105.563L315.328,478.864z M495.967,401.37
	c0,5.01-4.076,9.086-9.086,9.086H25.119c-5.01,0-9.086-4.076-9.086-9.086V93.528c0-5.01,4.076-9.086,9.086-9.086h182.899
	c2.367,6.835,6.151,13.007,11.005,18.171H42.221c-4.427,0-8.017,3.589-8.017,8.017v273.637c0,4.427,3.589,8.017,8.017,8.017h427.557
	c4.427,0,8.017-3.589,8.017-8.017V110.63c0-4.427-3.589-8.017-8.017-8.017H292.977c4.854-5.164,8.639-11.337,11.005-18.171h182.898
	c5.01,0,9.086,4.076,9.086,9.086V401.37z&quot;&gt;&lt;/path&gt;
&lt;path d=&quot;M256,84.443c9.136,0,16.568-7.432,16.568-16.568S265.136,51.307,256,51.307c-9.136,0-16.568,7.432-16.568,16.568
	S246.864,84.443,256,84.443z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
 &lt;/div&gt;
 

&lt;/figure&gt;

One of the most repeated pieces of advice for remote teams: turn cameras on, and people will be more engaged. At Team Falcon, the cameras are already on.&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Priya answers emails from the start of the meeting. Marcus keeps writing while the discussion happens around him. The camera captures their faces. Their attention is elsewhere.&lt;/p&gt;
&lt;p&gt;The problem is not visibility. It is engagement.&lt;/p&gt;
&lt;p&gt;People drift in meetings because the meeting gives them no reason to stay present. Open questions to the group get ignored. Passive listening becomes the norm. Nobody expects a direct question, so nobody prepares for one.&lt;/p&gt;
&lt;p&gt;Structure is what actually helps. Go around the room instead of waiting for volunteers. Ask specific people specific questions. Keep the standup under fifteen minutes with a hard stop. And when someone consistently checks out in a way that slows the whole group down, have that conversation directly, outside the standup.&lt;/p&gt;
&lt;h2 id=&quot;article-svniv03qER7W5bQ17EG4-fmY78w-what-owen-changed&quot;&gt;What Owen changed&lt;/h2&gt;
&lt;p&gt;Owen does not bring a list of complaints to that retrospective. Owen brings observations, patterns, and questions. That is the difference between venting and contributing.&lt;/p&gt;
&lt;p&gt;Naming those four things does not fix the process overnight. It gives the team the words for what was already true. The next step is an emergency retrospective outside the sprint, focused entirely on how the team wants to work. Not sprint content, not new stories. Just one question: how do we want to work, and what do we need to make that happen?&lt;/p&gt;
&lt;p&gt;Three concrete agreements come out of it. Not ten, only three:
&lt;/p&gt;&lt;figure&gt;

 
 &lt;div style=&quot;width: 200px&quot;&gt;
 
&lt;svg viewbox=&quot;0 0 64 64&quot; data-name=&quot;Layer 1&quot; id=&quot;article-svniv03qER7W5bQ17EG4-fmY78w-Layer_1&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;defs&gt;&lt;/defs&gt;&lt;path d=&quot;M51,26v-1.02c0-.62,.29-1.21,.79-1.58,1.95-1.46,3.21-3.78,3.21-6.4,0-4.72-4.09-8.48-8.91-7.95-3.52,.39-6.44,3.17-6.99,6.67-.49,3.13,.85,5.99,3.11,7.68,.5,.37,.79,.96,.79,1.59v1.02&quot;&gt;&lt;/path&gt;&lt;rect height=&quot;8&quot; width=&quot;2&quot; x=&quot;46&quot; y=&quot;18&quot;&gt;&lt;/rect&gt;&lt;path d=&quot;M24.58,40.04l-3,1.29c-1.01,.43-2.15,.43-3.15,0l-3-1.29c-1.47-.63-2.42-2.08-2.42-3.68v-5.36c0-3.31,2.69-6,6-6h2c3.31,0,6,2.69,6,6v5.36c0,1.6-.95,3.05-2.42,3.68Z&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M33.14,46c-1.82-1.85-4.35-3-7.14-3h-3c0,1.66-1.34,3-3,3s-3-1.34-3-3h-3c-5.52,0-10,4.48-10,10v7H26l4-14h3.14Z&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M15,56h2c1.1,0,2,.9,2,2v2h-4v-4h0Z&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M10,32.73c-.29,.17-.64,.27-1,.27-1.1,0-2-.9-2-2s.9-2,2-2c.42,0,.81,.13,1.14,.36&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M30,32.73c.29,.17,.64,.27,1,.27,1.1,0,2-.9,2-2s-.9-2-2-2c-.42,0-.81,.13-1.14,.36&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M17,40.71l1.42,.61c1.01,.44,2.15,.44,3.16,0l1.42-.61v2.29c0,1.66-1.34,3-3,3s-3-1.34-3-3v-2.29Z&quot;&gt;&lt;/path&gt;&lt;polyline points=&quot;26 60 30 46 52 46 48 60&quot;&gt;&lt;/polyline&gt;&lt;path d=&quot;M26.4,28.38h-.01c-.57-.23-1.23-.38-2.06-.38-4.33,0-4.33,4-8.67,4-1.13,0-1.97-.27-2.66-.67v-.33c0-3.31,2.69-6,6-6h2c2.37,0,4.42,1.38,5.39,3.38h.01Z&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M27,35.6v-4.6c0-3.31-2.69-6-6-6h-2c-3.31,0-6,2.69-6,6v4h-2c-.55,0-1-.45-1-1v-3c0-5.52,4.48-10,10-10,2.76,0,5.26,1.12,7.07,2.93s2.93,4.31,2.93,7.07v3.18c0,.48-.34,.89-.8,.98l-2.2,.44Z&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M39,52c.55,0,1,.45,1,1s-.45,1-1,1v-2Z&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M20,37h0c-.11-.54,.24-1.07,.78-1.18l8.22-1.64v-2.86c0-4.79-3.61-8.98-8.38-9.3-5.24-.35-9.62,3.81-9.62,8.98v3h2v2h-2c-1.1,0-2-.9-2-2v-2.68c0-5.72,4.24-10.74,9.94-11.27,6.54-.62,12.06,4.53,12.06,10.95v3.18c0,.95-.67,1.77-1.61,1.96l-8.22,1.64c-.54,.11-1.07-.24-1.18-.78Z&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M20,60h-2v-2c0-.55-.45-1-1-1h-7c-.55,0-1-.45-1-1v-4c0-.27,.11-.52,.29-.71l1.29-1.29c.39-.39,1.02-.39,1.41,0h0c.39,.39,.39,1.02,0,1.41l-1,1v2.59h6c1.66,0,3,1.34,3,3v2Z&quot;&gt;&lt;/path&gt;&lt;rect height=&quot;2&quot; width=&quot;50&quot; x=&quot;2&quot; y=&quot;60&quot;&gt;&lt;/rect&gt;&lt;rect height=&quot;4&quot; rx=&quot;1&quot; ry=&quot;1&quot; width=&quot;10&quot; x=&quot;42&quot; y=&quot;26&quot;&gt;&lt;/rect&gt;&lt;path d=&quot;M51,30c0,2.21-1.79,4-4,4s-4-1.79-4-4&quot;&gt;&lt;/path&gt;&lt;circle cx=&quot;47&quot; cy=&quot;17&quot; r=&quot;2&quot;&gt;&lt;/circle&gt;&lt;rect height=&quot;4&quot; width=&quot;2&quot; x=&quot;46&quot; y=&quot;2&quot;&gt;&lt;/rect&gt;&lt;rect height=&quot;4&quot; transform=&quot;translate(5.55 29.02) rotate(-45)&quot; width=&quot;2&quot; x=&quot;36.81&quot; y=&quot;5.81&quot;&gt;&lt;/rect&gt;&lt;rect height=&quot;2&quot; width=&quot;4&quot; x=&quot;32&quot; y=&quot;16&quot;&gt;&lt;/rect&gt;&lt;rect height=&quot;2&quot; transform=&quot;translate(-7.45 34.41) rotate(-45)&quot; width=&quot;4&quot; x=&quot;35.81&quot; y=&quot;25.19&quot;&gt;&lt;/rect&gt;&lt;rect height=&quot;4&quot; transform=&quot;translate(-2.06 47.41) rotate(-45)&quot; width=&quot;2&quot; x=&quot;55.19&quot; y=&quot;24.19&quot;&gt;&lt;/rect&gt;&lt;rect height=&quot;2&quot; width=&quot;4&quot; x=&quot;58&quot; y=&quot;16&quot;&gt;&lt;/rect&gt;&lt;rect height=&quot;2&quot; transform=&quot;translate(10.94 42.02) rotate(-45)&quot; width=&quot;4&quot; x=&quot;54.19&quot; y=&quot;6.81&quot;&gt;&lt;/rect&gt;&lt;rect height=&quot;2&quot; width=&quot;2&quot; x=&quot;46&quot; y=&quot;36&quot;&gt;&lt;/rect&gt;&lt;rect height=&quot;2&quot; width=&quot;2&quot; x=&quot;43&quot; y=&quot;40&quot;&gt;&lt;/rect&gt;&lt;rect height=&quot;2&quot; width=&quot;2&quot; x=&quot;39&quot; y=&quot;42&quot;&gt;&lt;/rect&gt;&lt;/svg&gt;

 &lt;/div&gt;
 

&lt;/figure&gt;
&lt;p&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The daily has a timekeeper and ends at fifteen minutes. No exceptions.&lt;/li&gt;
&lt;li&gt;No story moves to “in progress” without acceptance criteria. Every team member holds that line.&lt;/li&gt;
&lt;li&gt;Every retrospective starts by asking: what was our action item last time, and what actually happened?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That sounds simple. It is. It also requires someone willing to say what everyone already knows.&lt;/p&gt;
&lt;p&gt;Team Falcon’s retrospective was not working. Not because of the tool, the format, or the remote setup. Because nobody had said so out loud.&lt;/p&gt;
&lt;p&gt;Until Owen did.&lt;/p&gt;</summary><author><name></name></author><source gr:stream-id="feed/https://feeds.feedburner.com/bartvanherck"><id>tag:google.com,2005:reader/feed/https://feeds.feedburner.com/bartvanherck</id><title type="html">The Testing Pirate</title><link rel="alternate" href="https://www.bartvanherck.com/" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1783429869000"><id gr:original-id="6a4cf8df4099040001d19e21">tag:google.com,2005:reader/item/0000071a000000f0</id><title type="html">Recent eye-catching testing articles</title><published>2026-07-07T13:11:09Z</published><updated>2026-07-07T13:11:09Z</updated><link rel="alternate" href="https://www.workroom-productions.com/recent-eye-catching-testing-articles/" type="text/html"></link><summary type="html">&lt;img class=&quot;bqrUnknownImgSize&quot; src=&quot;https://images.unsplash.com/photo-1760428509071-438af4bf98dc?crop=entropy&amp;amp;cs=tinysrgb&amp;amp;fit=max&amp;amp;fm=jpg&amp;amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDM3fHxzY3JvbGxzfGVufDB8fHx8MTc4MzQyOTM5N3ww&amp;amp;ixlib=rb-4.1.0&amp;amp;q=80&amp;amp;w=2000&quot; alt=&quot;Recent eye-catching testing articles&quot;&gt;&lt;p&gt;&lt;/p&gt;

&lt;iframe style=&quot;height: 450.0px; border: 0; width: 100%&quot; src=&quot;https://workroomprds.raindrop.page/recent-testing-public-72690735/embed/sort=-created?hide=header,+tags&quot; allow=&quot;autoplay; fullscreen; encrypted-media; clipboard-write; picture-in-picture; web-share&quot; sandbox=&quot;allow-same-origin allow-scripts allow-forms allow-popups allow-presentation&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;</summary><author><name>James Lyndsay</name></author><source gr:stream-id="feed/https://www.workroom-productions.com/rss/"><id>tag:google.com,2005:reader/feed/https://www.workroom-productions.com/rss/</id><title type="html">Workroom Productions</title><link rel="alternate" href="https://www.workroom-productions.com/" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1783426624000"><id gr:original-id="https://medium.com/p/d58e751293b3">tag:google.com,2005:reader/item/00000a060000008f</id><category term="open-source"></category><category term="data-engineering"></category><category term="ideas"></category><category term="llm"></category><category term="ai"></category><title type="html">Pxpipe: The Token-Saving Hack That Turns LLM Context Into Images</title><published>2026-07-07T12:17:04Z</published><updated>2026-07-07T12:17:04Z</updated><link rel="alternate" href="https://pub.towardsai.net/pxpipe-the-token-saving-hack-that-turns-llm-context-into-images-d58e751293b3?source=rss-f171d77cdec6------2" type="text/html"></link><summary type="html">&lt;div&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://pub.towardsai.net/pxpipe-the-token-saving-hack-that-turns-llm-context-into-images-d58e751293b3?source=rss-f171d77cdec6------2&quot;&gt;&lt;img class=&quot;bqrUnknownImgSize&quot; src=&quot;https://cdn-images-1.medium.com/max/1450/1*CcVx-pii8pPmqeLwAWv3wQ.png&quot; width=&quot;1450&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;A practical deep dive into how Pxpipe reduces Claude Code input tokens by rendering bulky context as PNGs, why the trick works, and where…&lt;/p&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://pub.towardsai.net/pxpipe-the-token-saving-hack-that-turns-llm-context-into-images-d58e751293b3?source=rss-f171d77cdec6------2&quot;&gt;Continue reading on Towards AI »&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;</summary><author><name>TONI RAMCHANDANI</name></author><source gr:stream-id="feed/https://toniramchandani.medium.com/feed"><id>tag:google.com,2005:reader/feed/https://toniramchandani.medium.com/feed</id><title type="html">Stories by TONI RAMCHANDANI on Medium</title><link rel="alternate" href="https://medium.com/@toniramchandani?source=rss-f171d77cdec6------2" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1783419177000"><id gr:original-id="https://reframequality.com/?p=3479">tag:google.com,2005:reader/item/0000103100000009</id><category term="Cost of Poor Quality (COPQ)"></category><category term="Regulatory"></category><category term="Test Strategy"></category><title type="html">Your Regulatory Time Bomb: When Compliance Theatre Meets Reality</title><published>2026-07-07T10:12:57Z</published><updated>2026-07-07T10:12:57Z</updated><link rel="alternate" href="https://reframequality.com/your-regulatory-time-bomb-when-compliance-theatre-meets-reality/" type="text/html"></link><summary type="html">&lt;p&gt;On the opening weekend of this year’s Giro d’Italia Women, Lorena Wiebes won the first stage in a bunch sprint, pulled on the race leader’s jersey, and was disqualified a few hours later. The reason had nothing to do with how she rode. Her bike weighed 6.78 kilograms against a mandatory minimum of 6.8. Her team pointed out that the same bike had been weighed several times already this season, always comfortably above the limit, and that a second weighing on the same day produced a reading fifty grams different from the first. Nothing about the bicycle changed between those two readings. What changed was which number the process happened to catch.&lt;/p&gt;



&lt;p&gt;That small, brutal episode is a useful way into a much larger problem sitting inside enterprise technology right now: the difference between passing a compliance check and actually managing risk, and how rarely leadership discovers which one they have until a regulator, an auditor, or an attacker finds out first.&lt;/p&gt;



&lt;figure&gt;&lt;img width=&quot;1159&quot; height=&quot;576&quot; fetchpriority=&quot;high&quot; decoding=&quot;async&quot; alt data-orig-srcset=&quot;https://reframequality.com/wp-content/uploads/2026/07/Post-10-picture-3-edited.png 1159w, https://reframequality.com/wp-content/uploads/2026/07/Post-10-picture-3-edited-200x99.png 200w&quot; src=&quot;https://reframequality.com/wp-content/uploads/2026/07/Post-10-picture-3-edited.png&quot;&gt;&lt;/figure&gt;



&lt;p&gt;&lt;strong&gt;A Pass/Fail Reading Is Not a Risk Assessment&lt;/strong&gt;&lt;/p&gt;



&lt;div&gt;
&lt;p&gt;The UCI’s minimum weight rule was introduced in 2000 to stop bikes becoming dangerously light as carbon fibre took over the peloton. Since then, the UCI has built a genuinely thorough safety regime around equipment: frames must be submitted for approval against ISO 4210 structural standards, wheels must pass impact testing, and a clarification guide running to more than eighty pages governs everything from tube dimensions to handlebar geometry. None of that machinery was in question when Wiebes was disqualified. A single scale reading was.&lt;/p&gt;
&lt;/div&gt;



&lt;p&gt;That is the pattern worth noticing. A rule can be strictly enforced, produce a clean binary outcome, and still measure almost nothing about the risk it was originally written to prevent. Twenty grams is roughly the weight of four sugar cubes. It says nothing about whether a frame holds under load on a mountain descent. It says only what the scale read that afternoon.&lt;/p&gt;



&lt;p&gt;Compliance theatre works the same way inside a business. A checklist gets completed. A control is marked “implemented.” A privacy policy gets published. The dashboard reads green. Whether any of it says something true about the underlying risk is a separate question, and it is the one that rarely gets asked until something goes wrong.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;The Reverse Failure Is Just as Expensive&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;Sometimes the theatre runs the other way: every box ticked, and the real vulnerability sitting untested underneath. When Meta’s “View As” feature exposed data belonging to 29 million Facebook accounts in 2018, the eventual regulatory finding was not simply that a bug existed. Investigators concluded the breach could have been prevented with more thorough testing of the feature before release. The controls, the sign-offs and the policies had all been present. The specific interaction that let attackers generate access tokens through the feature had not been examined closely enough to catch it.&lt;/p&gt;



&lt;p&gt;The financial consequences of that gap between documented compliance and demonstrated risk management keep compounding. DLA Piper’s most recent GDPR enforcement survey put fines issued across a single twelve-month period at €1.2 billion, spanning financial services, healthcare, retail, energy and the public sector. Several 2024 enforcement decisions explicitly cited the absence of demonstrable technical controls, encryption and audit logging as evidence of negligence rather than misfortune.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;What Genuine Evidence Actually Looks Like&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;Professional cycling already runs a working example of the alternative, and it is not the bike-weighing scale. It is the Athlete Biological Passport. Rather than a single test looking for one substance at one moment, the passport tracks a rider’s blood markers over years, building a personal baseline and flagging only genuine deviation from it. The rider becomes their own point of reference. A result only carries weight when it breaks a longitudinal pattern, not when it crosses a fixed external line taken once.&lt;/p&gt;



&lt;p&gt;That is the distinction leadership should be drawing between documentation and evidence. Documentation says a control exists. Evidence shows the control holding under the conditions that matter, tracked over time, against the organisation’s own risk baseline rather than a generic template lifted from last year’s audit pack. One is a policy binder. The other is a testing strategy doing its job.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;The Forensic Arithmetic&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;Consider what a mid-sized financial services firm might carry into a serious enforcement action. At the fine levels cited above, a single case can run into eight figures before legal costs, remediation and customer notification are added. Layer on CISQ’s long-standing estimate that the cost of poor quality typically runs 15–20% of revenue in organisations that discover risk only after it materialises, and the arithmetic turns uncomfortable quickly: a business with genuinely tested controls is not spending less on compliance. It is spending the same money on something that actually works.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;THE LEADERSHIP QUESTION&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;&lt;em&gt;&lt;mark style=&quot;background-color: #abb8c3&quot;&gt;“When regulators or auditors ask ‘how do you know?’—can your testing provide evidence, or just documentation?”&lt;/mark&gt;&lt;/em&gt;&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;The Path Forward&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;None of this requires an army of new auditors or another layer of governance theatre. It requires testing designed to answer the question a regulator will actually ask, rather than the one a checklist assumes. Previously in this blog, we talked about customer trust as the asset your testing strategy protects; regulatory resilience is the other half of that same asset. Trust built on a compliance function that has never actually been tested is trust you have not yet earned.&lt;/p&gt;



&lt;p&gt;The good news, and it is genuinely good news, is that this is within reach. Testing teams that already think in terms of risk are best placed to build it: establish what “normal” looks like for your own systems, track deviation over time rather than relying on point-in-time snapshots, and make sure every control produces evidence a regulator could follow, not just a policy they could read. Organisations that do this do not merely survive an audit. They walk into one already knowing what it will find, because they found it first.&lt;/p&gt;



&lt;p&gt;That is worth doing. It is worth doing because the alternative is discovering, the way Lorena Wiebes did, that the gap between a career-defining win and a very public disqualification can come down to twenty grams, a scale nobody recalibrated, and a system nobody thought to test until the moment it mattered most.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Sources&lt;/strong&gt;:&lt;/p&gt;



&lt;ul&gt;
&lt;li&gt;&lt;em&gt;DLA Piper. (2025). GDPR Fines and Data Breach Survey.&lt;/em&gt;&lt;/li&gt;



&lt;li&gt;&lt;em&gt;ComplyDog. (2025). Biggest GDPR Fines of 2025.&lt;/em&gt;&lt;/li&gt;



&lt;li&gt;&lt;em&gt;Cyclingnews, &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;http://road.cc&quot;&gt;road.cc&lt;/a&gt;, Velora Cycling and VeloNews/Outside. (2026). Reporting on Lorena Wiebes’ disqualification from the Giro d’Italia Women, stage 1.&lt;/em&gt;&lt;/li&gt;



&lt;li&gt;&lt;em&gt;Escape Collective; Sports.legal; World Anti-Doping Agency (WADA). Explainers on the Athlete Biological Passport.&lt;/em&gt;&lt;/li&gt;



&lt;li&gt;&lt;em&gt;Consortium for Information &amp;amp; Software Quality (CISQ). Cost of Poor Software Quality research. &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.it-cisq.org/&quot;&gt;https://www.it-cisq.org/&lt;/a&gt;&lt;/em&gt;&lt;/li&gt;&lt;/ul&gt;</summary><author><name>Matt</name></author><source gr:stream-id="feed/https://reframequality.com/feed/"><id>tag:google.com,2005:reader/feed/https://reframequality.com/feed/</id><title type="html">ReframeQuality Blog</title><link rel="alternate" href="https://reframequality.com" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1783407600000"><id gr:original-id="https://testingil.com/?p=9514">tag:google.com,2005:reader/item/0000025700000113</id><category term="Uncategorized"></category><title type="html">Test The Feature: Now With Examples!</title><published>2026-07-07T07:00:00Z</published><updated>2026-07-07T07:00:00Z</updated><link rel="alternate" href="https://testingil.com/2026/07/test-the-feature-now-with-examples.html" type="text/html"></link><summary type="html">&lt;p&gt;In my &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://testingil.com/2026/06/test-the-feature-not-the-endpoint.html&quot; title=&quot;Test the Feature, Not the Endpoint&quot;&gt;last  post&lt;/a&gt;, I talked about how it’s more important to test the feature than the single API. Let’s explore this.&lt;/p&gt;



&lt;p&gt;In my Bigger Better Bookstore&lt;sup&gt;TM&lt;/sup&gt; I have a POST API for adding a review: &lt;/p&gt;


&lt;pre&gt;&lt;span&gt;&lt;code class=&quot;language-hljs language-javascript&quot;&gt;/books/{book[&lt;span&gt;&amp;apos;id&amp;apos;&lt;/span&gt;]}/reviews&lt;/code&gt;&lt;/span&gt;&lt;/pre&gt;


&lt;p&gt; We can write a test like this: &lt;/p&gt;


&lt;pre&gt;&lt;span&gt;&lt;code class=&quot;language-hljs language-javascript&quot;&gt;def test_add_review():
    book = &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;http://requests.post&quot;&gt;requests.post&lt;/a&gt;(f&lt;span&gt;&amp;quot;{BASE_URL}/books&amp;quot;&lt;/span&gt;, json={&lt;span&gt;&amp;quot;title&amp;quot;&lt;/span&gt;: &lt;span&gt;&amp;quot;Clean Code&amp;quot;&lt;/span&gt;, &lt;span&gt;&amp;quot;author&amp;quot;&lt;/span&gt;: &lt;span&gt;&amp;quot;Robert Martin&amp;quot;&lt;/span&gt;}).json()

    review_data = {
        &lt;span&gt;&amp;quot;rating&amp;quot;&lt;/span&gt;: &lt;span&gt;5&lt;/span&gt;,
        &lt;span&gt;&amp;quot;comment&amp;quot;&lt;/span&gt;: &lt;span&gt;&amp;quot;Excellent book on software craftsmanship!&amp;quot;&lt;/span&gt;,
        &lt;span&gt;&amp;quot;user_id&amp;quot;&lt;/span&gt;: &lt;span&gt;&amp;quot;user-1&amp;quot;&lt;/span&gt;,
    }
    response = &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;http://requests.post&quot;&gt;requests.post&lt;/a&gt;(f&lt;span&gt;&amp;quot;{BASE_URL}/books/{book[&amp;apos;id&amp;apos;]}/reviews&amp;quot;&lt;/span&gt;, json=review_data, headers=AUTH_HEADER)
    assert response.status_code == &lt;span&gt;201&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;&lt;/pre&gt;


&lt;p&gt;While it looks nice, we know that just checking the status code can be, let’s say very optimistic. Meaning, Even if the status code returns a 201, that doesn’t gives confidence that everything’s ok. So, first we add some checks:&lt;/p&gt;


&lt;pre&gt;&lt;span&gt;&lt;code class=&quot;language-hljs language-javascript&quot;&gt;def test_response_values_match_input(book):
    book_id = book[&lt;span&gt;&amp;quot;id&amp;quot;&lt;/span&gt;]
    resp = &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;http://requests.post&quot;&gt;requests.post&lt;/a&gt;(
        f&lt;span&gt;&amp;quot;{BASE_URL}/books/{book_id}/reviews&amp;quot;&lt;/span&gt;,
        json={&lt;span&gt;&amp;quot;rating&amp;quot;&lt;/span&gt;: &lt;span&gt;3&lt;/span&gt;, &lt;span&gt;&amp;quot;comment&amp;quot;&lt;/span&gt;: &lt;span&gt;&amp;quot;Decent read&amp;quot;&lt;/span&gt;},
        headers=AUTH_HEADER,
    )
    body = resp.json()
    assert body[&lt;span&gt;&amp;quot;rating&amp;quot;&lt;/span&gt;] == &lt;span&gt;3&lt;/span&gt;
    assert body[&lt;span&gt;&amp;quot;comment&amp;quot;&lt;/span&gt;] == &lt;span&gt;&amp;quot;Decent read&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;&lt;/pre&gt;


&lt;p&gt;Here’s a better check. What we sent as an input gets mirrored back to us in the response. But who says the APIs code just does the mirroring and nothing else?&lt;/p&gt;



&lt;p&gt;Here’s where “test the feature, not the API” comes in. We’re not really interested in the POST end point. We’re really interested in the book review. So, right now we’re interested in adding it, but the next thing would be to see if we can retrieve it:&lt;/p&gt;


&lt;pre&gt;&lt;span&gt;&lt;code class=&quot;language-hljs language-javascript&quot;&gt;def test_created_review_appears_in_book_list(book):
    review = add_review(book[&lt;span&gt;&amp;quot;id&amp;quot;&lt;/span&gt;], comment=&lt;span&gt;&amp;quot;Great chapter&amp;quot;&lt;/span&gt;)
    reviews = requests.get(f&lt;span&gt;&amp;quot;{BASE_URL}/books/{book[&amp;apos;id&amp;apos;]}/reviews&amp;quot;&lt;/span&gt;).json()
    ids = [r[&lt;span&gt;&amp;quot;id&amp;quot;&lt;/span&gt;] &lt;span&gt;for&lt;/span&gt; r &lt;span&gt;in&lt;/span&gt; reviews]
    assert review[&lt;span&gt;&amp;quot;id&amp;quot;&lt;/span&gt;] &lt;span&gt;in&lt;/span&gt; ids


def test_created_review_appears_in_all_reviews(book):
    review = add_review(book[&lt;span&gt;&amp;quot;id&amp;quot;&lt;/span&gt;], comment=&lt;span&gt;&amp;quot;Loved it&amp;quot;&lt;/span&gt;)
    all_reviews = requests.get(f&lt;span&gt;&amp;quot;{BASE_URL}/reviews&amp;quot;&lt;/span&gt;).json()
    ids = [r[&lt;span&gt;&amp;quot;id&amp;quot;&lt;/span&gt;] &lt;span&gt;for&lt;/span&gt; r &lt;span&gt;in&lt;/span&gt; all_reviews]
    assert review[&lt;span&gt;&amp;quot;id&amp;quot;&lt;/span&gt;] &lt;span&gt;in&lt;/span&gt; ids&lt;/code&gt;&lt;/span&gt;&lt;/pre&gt;


&lt;p&gt; Not just GET it. See, in the application, we need to see the review at least in two places (which are retrieved by different APIs). The first is in the “show me the all the reviews for this book”, and the other is “show me the reviews of all the books”. &lt;/p&gt;



&lt;p&gt;Did I extend the scope? Of course, because the feature extends over APIs. Like a DELETE:&lt;/p&gt;


&lt;pre&gt;&lt;span&gt;&lt;code class=&quot;language-hljs language-javascript&quot;&gt;def test_delete_review_removed_from_book_list(book):
    review = add_review(book[&lt;span&gt;&amp;quot;id&amp;quot;&lt;/span&gt;], comment=&lt;span&gt;&amp;quot;To be deleted&amp;quot;&lt;/span&gt;)
    requests.delete(f&lt;span&gt;&amp;quot;{BASE_URL}/books/{book[&amp;apos;id&amp;apos;]}/reviews/{review[&amp;apos;id&amp;apos;]}&amp;quot;&lt;/span&gt;, headers=USER1)
    reviews = requests.get(f&lt;span&gt;&amp;quot;{BASE_URL}/books/{book[&amp;apos;id&amp;apos;]}/reviews&amp;quot;&lt;/span&gt;).json()
    assert review[&lt;span&gt;&amp;quot;id&amp;quot;&lt;/span&gt;] not &lt;span&gt;in&lt;/span&gt; [r[&lt;span&gt;&amp;quot;id&amp;quot;&lt;/span&gt;] &lt;span&gt;for&lt;/span&gt; r &lt;span&gt;in&lt;/span&gt; reviews]


def test_delete_review_removed_from_all_reviews(book):
    review = add_review(book[&lt;span&gt;&amp;quot;id&amp;quot;&lt;/span&gt;], comment=&lt;span&gt;&amp;quot;Also gone&amp;quot;&lt;/span&gt;)
    requests.delete(f&lt;span&gt;&amp;quot;{BASE_URL}/books/{book[&amp;apos;id&amp;apos;]}/reviews/{review[&amp;apos;id&amp;apos;]}&amp;quot;&lt;/span&gt;, headers=USER1)
    all_reviews = requests.get(f&lt;span&gt;&amp;quot;{BASE_URL}/reviews&amp;quot;&lt;/span&gt;).json()
    assert review[&lt;span&gt;&amp;quot;id&amp;quot;&lt;/span&gt;] not &lt;span&gt;in&lt;/span&gt; [r[&lt;span&gt;&amp;quot;id&amp;quot;&lt;/span&gt;] &lt;span&gt;for&lt;/span&gt; r &lt;span&gt;in&lt;/span&gt; all_reviews]
&lt;/code&gt;&lt;/span&gt;&lt;/pre&gt;


&lt;p&gt;Again, the DELETE by itself is not interesting. The impact is about what happens after the deletion. In our example, it’s that the review doesn’t appear in the two lists. &lt;/p&gt;



&lt;p&gt;But, the feature is getting bigger. &lt;/p&gt;


&lt;pre&gt;&lt;span&gt;&lt;code class=&quot;language-hljs language-javascript&quot;&gt;
def test_no_duplicate_review_ids(book):
    &lt;span&gt;with&lt;/span&gt; concurrent.futures.ThreadPoolExecutor(max_workers=THREAD_COUNT) &lt;span&gt;as&lt;/span&gt; executor:
        futures = [executor.submit(submit_review, book[&lt;span&gt;&amp;quot;id&amp;quot;&lt;/span&gt;], i) &lt;span&gt;for&lt;/span&gt; i &lt;span&gt;in&lt;/span&gt; range(THREAD_COUNT)]
        responses = [f.result() &lt;span&gt;for&lt;/span&gt; f &lt;span&gt;in&lt;/span&gt; concurrent.futures.as_completed(futures)]

    ids = [r.json()[&lt;span&gt;&amp;quot;id&amp;quot;&lt;/span&gt;] &lt;span&gt;for&lt;/span&gt; r &lt;span&gt;in&lt;/span&gt; responses]
    assert len(ids) == len(&lt;span&gt;set&lt;/span&gt;(ids))&lt;/code&gt;&lt;/span&gt;&lt;/pre&gt;


&lt;p&gt;This test checks what happens when many users call the API at the same time. This check is very simple, that the IDs sent are the same ones received. It can be tightened more, like if they entered on the right order.&lt;/p&gt;



&lt;p&gt;The feature does feel a lot bigger than we thought. And part of it is because we’re focusing on number of APIs and status codes. The truth is, features are logical combinations of API calls.&lt;/p&gt;



&lt;h2&gt;Can there be more?&lt;/h2&gt;



&lt;p&gt;You betcha. Lot’s more. A small review feature can be tested in many different ways. And we should test it, because that’s the way users are going to call the APIs.&lt;/p&gt;



&lt;p&gt;Here are a couple of things to check more&lt;/p&gt;



&lt;ul&gt;
&lt;li&gt;Our review service depends on a moderation service. What happens when the moderation service on goes down?&lt;/li&gt;



&lt;li&gt;We checked concurrency for 300 people. Now make it 300,000. Is the server still breathing? &lt;/li&gt;



&lt;li&gt;And the one we always forget – can &lt;em&gt;I&lt;/em&gt; delete &lt;em&gt;your&lt;/em&gt; review? Can you edit &lt;em&gt;mine&lt;/em&gt;?&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;Can there be more? Suggestions in comments, please.&lt;/p&gt;



&lt;p&gt;On July 15th I’m running a free webinar – &lt;strong&gt;Assertions You Can Trust&lt;/strong&gt;. I walk through the questions, principles and yes, prompts to create a suite of tests for your features  – that you can trust.&lt;/p&gt;



&lt;p&gt;&lt;img class=&quot;bqrUnknownImgSize&quot; src=&quot;https://s.w.org/images/core/emoji/17.0.2/72x72/1f449.png&quot; alt=&quot;👉&quot; style=&quot;height: 1em&quot;&gt; &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://us02web.zoom.us/webinar/register/1617677800254/WN_KIU_7yUpRr2yZ8wId1tgSg&quot; title&gt;Save your seat&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;&lt;img class=&quot;bqrUnknownImgSize&quot; src=&quot;https://s.w.org/images/core/emoji/17.0.2/72x72/1f527.png&quot; alt=&quot;🔧&quot; style=&quot;height: 1em&quot;&gt; &lt;strong&gt;The API Testing Masterclass: The Tactician&lt;/strong&gt; — test design, assertions, debugging, and AI-powered testing. Coming soon.&lt;br&gt;&lt;img class=&quot;bqrUnknownImgSize&quot; src=&quot;https://s.w.org/images/core/emoji/17.0.2/72x72/1f449.png&quot; alt=&quot;👉&quot; style=&quot;height: 1em&quot;&gt; &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://testingil.com/mc-api-testing-tactician&quot;&gt;Join the waitlist&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;&lt;img class=&quot;bqrUnknownImgSize&quot; src=&quot;https://s.w.org/images/core/emoji/17.0.2/72x72/1f4da.png&quot; alt=&quot;📚&quot; style=&quot;height: 1em&quot;&gt; &lt;strong&gt;The Strategist Masterclass&lt;/strong&gt; — Improve API quality strategy at the organizational level.&lt;br&gt;&lt;img class=&quot;bqrUnknownImgSize&quot; src=&quot;https://s.w.org/images/core/emoji/17.0.2/72x72/1f449.png&quot; alt=&quot;👉&quot; style=&quot;height: 1em&quot;&gt; &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://testingil.com/mc-api-testing-strategist&quot;&gt;Join the waitlist&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;The post &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://testingil.com/2026/07/test-the-feature-now-with-examples.html&quot;&gt;Test The Feature: Now With Examples!&lt;/a&gt; first appeared on &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://testingil.com&quot;&gt;TestinGil&lt;/a&gt;.</summary><author><name>Gil Zilberfeld</name></author><source gr:stream-id="feed/http://www.everydayunittesting.com/feed"><id>tag:google.com,2005:reader/feed/http://www.everydayunittesting.com/feed</id><title type="html">Everyday Unit Testing</title><link rel="alternate" href="https://testingil.com" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1783398874000"><id gr:original-id="https://scrolltest.com/ai-testing-evidence-green-checks/">tag:google.com,2005:reader/item/0000044400000289</id><category term="AI Testing"></category><category term="Test Automation"></category><category term="Testing"></category><category term="CI/CD"></category><category term="SDET"></category><category term="test automation"></category><title type="html">AI Testing Evidence: Stop Trusting Green Checks</title><published>2026-07-07T04:34:34Z</published><updated>2026-07-07T04:34:34Z</updated><link rel="alternate" href="https://scrolltest.com/ai-testing-evidence-green-checks/" type="text/html"></link><summary type="html">&lt;p&gt;AI testing evidence is the difference between a useful browser agent and a green checkmark that quietly missed the risk.&lt;/p&gt;
&lt;p&gt;The post &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; rel=&quot;nofollow&quot; href=&quot;https://scrolltest.com/ai-testing-evidence-green-checks/&quot;&gt;AI Testing Evidence: Stop Trusting Green Checks&lt;/a&gt; appeared first on &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; rel=&quot;nofollow&quot; href=&quot;https://scrolltest.com&quot;&gt;Software Testing &amp;amp; Automation&lt;/a&gt;.&lt;/p&gt;</summary><author><name>Promode</name></author><source gr:stream-id="feed/https://scrolltest.com/feed/"><id>tag:google.com,2005:reader/feed/https://scrolltest.com/feed/</id><title type="html">Software Testing &amp; Automation</title><link rel="alternate" href="https://scrolltest.com" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1783396260000"><id gr:original-id="https://medium.com/p/f08da81fef17">tag:google.com,2005:reader/item/00000a87000000c2</id><category term="quality-assurance"></category><category term="sdet"></category><category term="software-testing"></category><category term="test-automation"></category><category term="software-engineering"></category><title type="html">The Most Valuable SDET Skill Is No Longer Test Automation</title><published>2026-07-07T03:51:00Z</published><updated>2026-07-07T03:51:00Z</updated><link rel="alternate" href="https://manishsaini74.medium.com/the-most-valuable-sdet-skill-is-no-longer-test-automation-f08da81fef17?source=rss-2afcb904d789------2" type="text/html"></link><summary type="html">&lt;div&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://manishsaini74.medium.com/the-most-valuable-sdet-skill-is-no-longer-test-automation-f08da81fef17?source=rss-2afcb904d789------2&quot;&gt;&lt;img class=&quot;bqrUnknownImgSize&quot; src=&quot;https://cdn-images-1.medium.com/max/1536/1*Sy92CNSHWp_DOWwwINZxnQ.png&quot; width=&quot;1536&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;For years, the career path for an SDET was relatively clear.&lt;/p&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://manishsaini74.medium.com/the-most-valuable-sdet-skill-is-no-longer-test-automation-f08da81fef17?source=rss-2afcb904d789------2&quot;&gt;Continue reading on Medium »&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;</summary><author><name>Manish Saini</name></author><source gr:stream-id="feed/https://manishsaini74.medium.com/feed"><id>tag:google.com,2005:reader/feed/https://manishsaini74.medium.com/feed</id><title type="html">Stories by Manish Saini on Medium</title><link rel="alternate" href="https://medium.com/@manishsaini74?source=rss-2afcb904d789------2" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1783395789000"><id gr:original-id="https://scrolltest.com/playwright-upgrade-checklist-blind-updates/">tag:google.com,2005:reader/item/0000044400000288</id><category term="Javascript"></category><category term="Test Automation"></category><category term="Testing"></category><category term="CI/CD"></category><category term="Playwright"></category><category term="Release Notes"></category><category term="SDET"></category><category term="test automation"></category><title type="html">Playwright Upgrade Checklist: Stop Blind Updates</title><published>2026-07-07T03:43:09Z</published><updated>2026-07-07T03:43:09Z</updated><link rel="alternate" href="https://scrolltest.com/playwright-upgrade-checklist-blind-updates/" type="text/html"></link><summary type="html">&lt;p&gt;A practical Playwright upgrade checklist for QA teams that want safer releases: read the note, pin the version, run one critical journey, inspect trace evidence, compare screenshots, and ship or rollback.&lt;/p&gt;
&lt;p&gt;The post &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; rel=&quot;nofollow&quot; href=&quot;https://scrolltest.com/playwright-upgrade-checklist-blind-updates/&quot;&gt;Playwright Upgrade Checklist: Stop Blind Updates&lt;/a&gt; appeared first on &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; rel=&quot;nofollow&quot; href=&quot;https://scrolltest.com&quot;&gt;Software Testing &amp;amp; Automation&lt;/a&gt;.&lt;/p&gt;</summary><author><name>Promode</name></author><source gr:stream-id="feed/https://scrolltest.com/feed/"><id>tag:google.com,2005:reader/feed/https://scrolltest.com/feed/</id><title type="html">Software Testing &amp; Automation</title><link rel="alternate" href="https://scrolltest.com" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1783395520000"><id gr:original-id="https://scrolltest.com/browser-agent-test-evidence-qa-approval-guide/">tag:google.com,2005:reader/item/0000044400000287</id><category term="AI Testing"></category><category term="Testing"></category><category term="Release Notes"></category><category term="SDET"></category><category term="test automation"></category><title type="html">Browser Agent Test Evidence: QA Approval Guide</title><published>2026-07-07T03:38:40Z</published><updated>2026-07-07T03:38:40Z</updated><link rel="alternate" href="https://scrolltest.com/browser-agent-test-evidence-qa-approval-guide/" type="text/html"></link><summary type="html">&lt;p&gt;Browser agent test evidence is the difference between a useful AI browser run and a risky green check. This guide gives QA teams a practical approval model.&lt;/p&gt;
&lt;p&gt;The post &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; rel=&quot;nofollow&quot; href=&quot;https://scrolltest.com/browser-agent-test-evidence-qa-approval-guide/&quot;&gt;Browser Agent Test Evidence: QA Approval Guide&lt;/a&gt; appeared first on &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; rel=&quot;nofollow&quot; href=&quot;https://scrolltest.com&quot;&gt;Software Testing &amp;amp; Automation&lt;/a&gt;.&lt;/p&gt;</summary><author><name>Promode</name></author><source gr:stream-id="feed/https://scrolltest.com/feed/"><id>tag:google.com,2005:reader/feed/https://scrolltest.com/feed/</id><title type="html">Software Testing &amp; Automation</title><link rel="alternate" href="https://scrolltest.com" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1783393200000"><id gr:original-id="https://scrolltest.com/?p=8187">tag:google.com,2005:reader/item/0000044400000286</id><category term="Playwright tutorial Java"></category><category term="Testing"></category><title type="html">Network Throttling and Offline Testing in Playwright</title><published>2026-07-07T03:00:00Z</published><updated>2026-07-07T03:00:00Z</updated><link rel="alternate" href="https://scrolltest.com/playwright-network-throttling-offline/" type="text/html"></link><summary type="html">&lt;p&gt;Learn Playwright network throttling and offline testing in TypeScript: offline mode, CDP Slow 3G throttling, per-request delays, and HAR replay.&lt;/p&gt;
&lt;p&gt;The post &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; rel=&quot;nofollow&quot; href=&quot;https://scrolltest.com/playwright-network-throttling-offline/&quot;&gt;Network Throttling and Offline Testing in Playwright&lt;/a&gt; appeared first on &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; rel=&quot;nofollow&quot; href=&quot;https://scrolltest.com&quot;&gt;Software Testing &amp;amp; Automation&lt;/a&gt;.&lt;/p&gt;</summary><author><name>Pramod Dutta</name></author><source gr:stream-id="feed/https://scrolltest.com/feed/"><id>tag:google.com,2005:reader/feed/https://scrolltest.com/feed/</id><title type="html">Software Testing &amp; Automation</title><link rel="alternate" href="https://scrolltest.com" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1783382400000"><id gr:original-id="https://josephward.tech/looking-behind-playwrights-magic-edited">tag:google.com,2005:reader/item/0000031900000011</id><title type="html">Looking Behind Playwright’s Magic</title><published>2026-07-07T00:00:00Z</published><updated>2026-07-07T00:00:00Z</updated><link rel="alternate" href="https://josephward.tech/2026-07-07-looking-behind-playwrights-magic-edited/" type="text/html"></link><summary type="html">&lt;p&gt;A Playwright click looks simple:&lt;/p&gt;

&lt;div&gt;&lt;div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;await&lt;/span&gt; &lt;span&gt;page&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getByRole&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;button&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;{&lt;/span&gt; &lt;span&gt;name&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;Submit&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt; &lt;span&gt;}).&lt;/span&gt;&lt;span&gt;click&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Chromium, however, cannot click “the button named Submit”. It can only receive input at an x,y position on the page. Before Playwright can send that action, it resolves the locator, determines whether the element can be interacted with, scrolls it into view, calculates its coordinates, and checks that another element will not receive the click instead.&lt;/p&gt;

&lt;p&gt;Even so, sending the action is only half the battle. The click may start a navigation, submit a form, open a new page, or trigger network requests. Playwright then needs to coordinate with what the browser does next.&lt;/p&gt;

&lt;p&gt;In a &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://josephward.tech/2024-01-21-harmonising-selenium/&quot;&gt;previous post&lt;/a&gt;, I used several approaches to observe Chrome DevTools Protocol (CDP) network events from Selenium. This time, I followed Playwright’s source to see how it turns those low-level browser signals into the higher-level behaviour behind a click.&lt;/p&gt;

&lt;p&gt;There are two paths to examine:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;how Playwright prepares and completes the action&lt;/li&gt;
  &lt;li&gt;how it observes and waits for the consequences.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This article follows the Chromium implementation, where Playwright talks to the browser using CDP. Firefox and WebKit provide the same high-level Playwright abstractions through different underlying code.&lt;/p&gt;

&lt;p&gt;All Playwright source links are pinned to commit &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://github.com/microsoft/playwright/commit/ad18048db947ca0a47c7fa59b77718e3a06afafe&quot;&gt;&lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;ad18048&lt;/code&gt;&lt;/a&gt; from 1 July 2026.&lt;/p&gt;

&lt;h2 id=&quot;article-xjFtekvhzHVua7p_q2CJz_TP4Us-it-starts-with-a-locator&quot;&gt;It starts with a locator&lt;/h2&gt;

&lt;p&gt;The trail begins in:&lt;/p&gt;

&lt;div&gt;&lt;div&gt;&lt;pre&gt;&lt;code&gt;packages/playwright-core/src/client/locator.ts
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;Locator.click()&lt;/code&gt; does not perform the click itself. It passes the locator’s selector to the frame and enables strict matching:&lt;/p&gt;

&lt;div&gt;&lt;div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;async&lt;/span&gt; &lt;span&gt;click&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;options&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;channels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ElementHandleClickOptions&lt;/span&gt; &lt;span&gt;&amp;amp;&lt;/span&gt; &lt;span&gt;TimeoutOptions&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;{}):&lt;/span&gt; &lt;span&gt;Promise&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;return&lt;/span&gt; &lt;span&gt;await&lt;/span&gt; &lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;_frame&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;click&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;_selector&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;{&lt;/span&gt; &lt;span&gt;strict&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;...&lt;/span&gt;&lt;span&gt;options&lt;/span&gt; &lt;span&gt;});&lt;/span&gt;
&lt;span&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That is the implementation in &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://github.com/microsoft/playwright/blob/ad18048db947ca0a47c7fa59b77718e3a06afafe/packages/playwright-core/src/client/locator.ts#L113-L115&quot;&gt;&lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;locator.ts&lt;/code&gt;, lines 113–115&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Those few lines reveal two useful design choices.&lt;/p&gt;

&lt;p&gt;First, the locator holds a selector rather than an element fetched earlier. Playwright can resolve it against the current document when the action is attempted. That matters on pages where a rendering framework may remove one node and insert another that represents the same thing. Resolving at action time avoids treating an old element reference as though it were still current.&lt;/p&gt;

&lt;p&gt;Second, &lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;strict: true&lt;/code&gt; means the action expects exactly one match. If the locator resolves to several buttons, Playwright reports an ambiguity instead of silently choosing the first.&lt;/p&gt;

&lt;p&gt;I prefer that failure mode. A selector matching several &lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;Submit&lt;/code&gt; buttons is usually a problem in the test or the interface, not something I want the framework to conceal.&lt;/p&gt;

&lt;p&gt;The call then crosses Playwright’s client/server boundary and eventually reaches the server-side element action code in:&lt;/p&gt;

&lt;div&gt;&lt;div&gt;&lt;pre&gt;&lt;code&gt;packages/playwright-core/src/server/dom.ts
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is where most of the pre-click “magic” becomes explicit logic.&lt;/p&gt;

&lt;h2 id=&quot;article-xjFtekvhzHVua7p_q2CJz_TP4Us-a-click-may-need-retrying&quot;&gt;A click may need retrying&lt;/h2&gt;

&lt;p&gt;The internal click path passes the work into Playwright’s element interaction code. The eventual mouse action is wrapped by &lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;_retryAction&lt;/code&gt;, which contains a retry loop shared by element operations.&lt;/p&gt;

&lt;p&gt;One of the first things it defines is a delay schedule:&lt;/p&gt;

&lt;div&gt;&lt;div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;// We progressively wait longer between retries, up to 500ms.&lt;/span&gt;
&lt;span&gt;const&lt;/span&gt; &lt;span&gt;waitTime&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;[&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;20&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;100&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;100&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;500&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The schedule appears in &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://github.com/microsoft/playwright/blob/ad18048db947ca0a47c7fa59b77718e3a06afafe/packages/playwright-core/src/server/dom.ts#L318-L319&quot;&gt;&lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;dom.ts&lt;/code&gt;, lines 318–319&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The loop attempts the action until it succeeds, encounters a non-retryable failure, or reaches the surrounding timeout. It handles results such as an element not being visible or lying outside the viewport. The branches are shown in &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://github.com/microsoft/playwright/blob/ad18048db947ca0a47c7fa59b77718e3a06afafe/packages/playwright-core/src/server/dom.ts#L297-L314&quot;&gt;&lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;dom.ts&lt;/code&gt;, lines 297–314&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This gives us a more useful description of auto-waiting than saying Playwright somehow knows when a page is “ready”. It does not need a universal definition of readiness. Instead, it asks a narrower and more understandable question: can this requested action proceed now?&lt;/p&gt;

&lt;p&gt;That distinction matters because many modern pages never become completely inactive. A page may keep a WebSocket open, poll for notifications, or continue loading secondary content after the main interface is usable. Waiting for the entire page to become abstractly “ready” would be both vague and, in some applications, impossible.&lt;/p&gt;

&lt;p&gt;For a click, the practical question is whether this particular target can receive this particular action.&lt;/p&gt;

&lt;h2 id=&quot;article-xjFtekvhzHVua7p_q2CJz_TP4Us-what-playwright-checks-before-sending-input&quot;&gt;What Playwright checks before sending input&lt;/h2&gt;

&lt;p&gt;For a normal click, Playwright checks several element states, including:&lt;/p&gt;

&lt;div&gt;&lt;div&gt;&lt;pre&gt;&lt;code&gt;visible
enabled
stable
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The Playwright-side logic calls &lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;injected.checkElementStates&lt;/code&gt; against the target. That path can be followed in &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://github.com/microsoft/playwright/blob/ad18048db947ca0a47c7fa59b77718e3a06afafe/packages/playwright-core/src/server/dom.ts#L432-L440&quot;&gt;&lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;dom.ts&lt;/code&gt;, lines 432–440&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Each state addresses a different failure mode.&lt;/p&gt;

&lt;p&gt;A node being present in the DOM does not mean it has useful geometry. A disabled control may be visible but should not receive a normal user action. A button may be visible and enabled while still moving across the page because of an animation.&lt;/p&gt;

&lt;p&gt;The stability check therefore observes the element across animation frames rather than adding the same fixed delay to every action.&lt;/p&gt;

&lt;p&gt;This does not make races impossible. The application can always change after a check. Playwright is just reducing a common timing window, not making the browser immune to change.&lt;/p&gt;

&lt;p&gt;Once those checks pass, Playwright scrolls the target into view. During retries, it can use different alignments rather than relying on one scroll position. The source comments explain why: a normal scroll may leave the element beneath an overlay, while another alignment may expose a usable point.&lt;/p&gt;

&lt;p&gt;Playwright then calculates a x,y coordinate from the element’s geometry.&lt;/p&gt;

&lt;p&gt;At this stage it has translated something semantic:&lt;/p&gt;

&lt;div&gt;&lt;div&gt;&lt;pre&gt;&lt;code&gt;the button named Submit
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;into something the browser’s input system can use:&lt;/p&gt;

&lt;div&gt;&lt;div&gt;&lt;pre&gt;&lt;code&gt;a point at x and y
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It still has to establish that the point belongs to the intended element at the moment of interaction.&lt;/p&gt;

&lt;h2 id=&quot;article-xjFtekvhzHVua7p_q2CJz_TP4Us-what-force-skips&quot;&gt;What &lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;force&lt;/code&gt; skips&lt;/h2&gt;

&lt;p&gt;Following this path also makes &lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;force: true&lt;/code&gt; less mysterious:&lt;/p&gt;

&lt;div&gt;&lt;div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;await&lt;/span&gt; &lt;span&gt;locator&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;click&lt;/span&gt;&lt;span&gt;({&lt;/span&gt; &lt;span&gt;force&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;true&lt;/span&gt; &lt;span&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The forced path skips Playwright’s normal actionability logic : the visible, enabled, and stable checks above, along with the hit-target check described next. It proceeds towards dispatching the input without requiring the usual evidence that a user could perform the action.&lt;/p&gt;

&lt;p&gt;I would read it as:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Attempt the action without Playwright first establishing user actionability.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It does not make the click more realistic. In fact, it arguably removes checks intended to establish realism.&lt;/p&gt;

&lt;p&gt;There are legitimate uses for this, but it can also hide the interesting problem. Perhaps a loading overlay never disappeared, the locator matched a hidden duplicate, or the control remained disabled.&lt;/p&gt;

&lt;p&gt;The network side remains separate. If forced input triggers a navigation or network requests, Playwright can still observe those browser events. The question is whether the test still demonstrates an interaction available to a user.&lt;/p&gt;

&lt;h2 id=&quot;article-xjFtekvhzHVua7p_q2CJz_TP4Us-visibility-is-not-targetabity&quot;&gt;Visibility is not targetabity&lt;/h2&gt;

&lt;p&gt;A visible element is not necessarily the element that would receive an action.&lt;/p&gt;

&lt;p&gt;A loading overlay might be nearly transparent, leaving the button visible to a person while still intercepting the click. An element can therefore pass a visibility check without being the browser’s target.&lt;/p&gt;

&lt;p&gt;Playwright uses injected code to check which element would receive the pointer event and to install a hit-target interceptor:&lt;/p&gt;

&lt;div&gt;&lt;div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;const&lt;/span&gt; &lt;span&gt;handle&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;await&lt;/span&gt; &lt;span&gt;progress&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;race&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;
  &lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;_evaluateHandleInUtility&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;
    &lt;span&gt;([&lt;/span&gt;&lt;span&gt;injected&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;node&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;{&lt;/span&gt; &lt;span&gt;actionType&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;hitPoint&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;trial&lt;/span&gt; &lt;span&gt;}])&lt;/span&gt; &lt;span&gt;=&amp;gt;&lt;/span&gt;
      &lt;span&gt;injected&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;setupHitTargetInterceptor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;node&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;actionType&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;hitPoint&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;trial&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;
    &lt;span&gt;{&lt;/span&gt; &lt;span&gt;actionType&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;hitPoint&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;trial&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;!!&lt;/span&gt;&lt;span&gt;options&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;trial&lt;/span&gt; &lt;span&gt;}&lt;/span&gt; &lt;span&gt;as&lt;/span&gt; &lt;span&gt;const&lt;/span&gt;
  &lt;span&gt;)&lt;/span&gt;
&lt;span&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This comes from &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://github.com/microsoft/playwright/blob/ad18048db947ca0a47c7fa59b77718e3a06afafe/packages/playwright-core/src/server/dom.ts#L470&quot;&gt;&lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;dom.ts&lt;/code&gt;, line 470&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If another element owns the ‘point’, Playwright returns a hit-target description to the outer retry loop. That is the source of errors reporting that a particular overlay or container intercepts pointer events.&lt;/p&gt;

&lt;p&gt;The result feeds back into the retry logic, which can decide whether to attempt the click again.&lt;/p&gt;

&lt;p&gt;Frames make the calculation more involved because the point must be checked through the frame hierarchy. Playwright performs a separate frame hit-target step before installing the interceptor, but I will leave most of that path unexplored here.&lt;/p&gt;

&lt;h2 id=&quot;article-xjFtekvhzHVua7p_q2CJz_TP4Us-chromium-receives-a-mouse-event&quot;&gt;Chromium receives a mouse event&lt;/h2&gt;

&lt;p&gt;Once the element checks, scrolling, and targetabity succeed, Playwright calls its mouse abstraction with the calculated point.&lt;/p&gt;

&lt;p&gt;For Chromium, the final implementation is in:&lt;/p&gt;

&lt;div&gt;&lt;div&gt;&lt;pre&gt;&lt;code&gt;packages/playwright-core/src/server/chromium/crInput.ts
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;RawMouseImpl&lt;/code&gt; sends the CDP command &lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;Input.dispatchMouseEvent&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A mouse move is dispatched like this:&lt;/p&gt;

&lt;div&gt;&lt;div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;await&lt;/span&gt; &lt;span&gt;progress&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;race&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;_client&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;send&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;Input.dispatchMouseEvent&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;type&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;mouseMoved&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;button&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;buttons&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;toButtonsMask&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;buttons&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;
  &lt;span&gt;x&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;y&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;modifiers&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;toModifiersMask&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;modifiers&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;
  &lt;span&gt;force&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;buttons&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;size&lt;/span&gt; &lt;span&gt;&amp;gt;&lt;/span&gt; &lt;span&gt;0&lt;/span&gt; &lt;span&gt;?&lt;/span&gt; &lt;span&gt;0.5&lt;/span&gt; &lt;span&gt;:&lt;/span&gt; &lt;span&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;span&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The implementation, including &lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;mousePressed&lt;/code&gt; and &lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;mouseReleased&lt;/code&gt;, is in &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://github.com/microsoft/playwright/blob/ad18048db947ca0a47c7fa59b77718e3a06afafe/packages/playwright-core/src/server/chromium/crInput.ts#L104-L164&quot;&gt;&lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;crInput.ts&lt;/code&gt;, lines 104–164&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is not the same as evaluating the following inside the page:&lt;/p&gt;

&lt;div&gt;&lt;div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;element&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;click&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The DOM method invokes the element’s programmatic click behaviour. The CDP route sends browser input at a position.&lt;/p&gt;

&lt;p&gt;That difference explains much of Playwright’s action code. Chromium’s input domain does not understand a ‘role selector’ or an ‘accessible name’. Playwright must resolve the semantic target, inspect its current state, and produce valid coordinates before Chromium can act on it.&lt;/p&gt;

&lt;p&gt;Now for the other side of the story…&lt;/p&gt;

&lt;h2 id=&quot;article-xjFtekvhzHVua7p_q2CJz_TP4Us-the-network-path-starts-in-crnetworkmanager&quot;&gt;The network path starts in &lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;crNetworkManager&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;The Chromium-specific network implementation is in:&lt;/p&gt;

&lt;div&gt;&lt;div&gt;&lt;pre&gt;&lt;code&gt;packages/playwright-core/src/server/chromium/crNetworkManager.ts
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When Playwright attaches a CDP session, it registers listeners for events from the browser’s Network and Fetch domains.&lt;/p&gt;

&lt;p&gt;The source includes:&lt;/p&gt;

&lt;div&gt;&lt;div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;eventsHelper&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;session&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;Fetch.requestPaused&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;...);&lt;/span&gt;
&lt;span&gt;eventsHelper&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;session&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;Fetch.authRequired&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;...);&lt;/span&gt;
&lt;span&gt;eventsHelper&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;session&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;Network.requestWillBeSent&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;...);&lt;/span&gt;
&lt;span&gt;eventsHelper&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;session&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;Network.requestWillBeSentExtraInfo&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;...);&lt;/span&gt;
&lt;span&gt;eventsHelper&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;session&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;Network.requestServedFromCache&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;...);&lt;/span&gt;
&lt;span&gt;eventsHelper&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;session&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;Network.responseReceived&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;...);&lt;/span&gt;
&lt;span&gt;eventsHelper&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;session&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;Network.responseReceivedExtraInfo&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;...);&lt;/span&gt;
&lt;span&gt;eventsHelper&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;session&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;Network.loadingFinished&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;...);&lt;/span&gt;
&lt;span&gt;eventsHelper&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;session&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;Network.loadingFailed&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;...);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Those registrations appear in &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://github.com/microsoft/playwright/blob/ad18048db947ca0a47c7fa59b77718e3a06afafe/packages/playwright-core/src/server/chromium/crNetworkManager.ts#L67-L75&quot;&gt;&lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;crNetworkManager.ts&lt;/code&gt;, lines 67–75&lt;/a&gt;. The same setup also registers WebSocket lifecycle and frame listeners in &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://github.com/microsoft/playwright/blob/ad18048db947ca0a47c7fa59b77718e3a06afafe/packages/playwright-core/src/server/chromium/crNetworkManager.ts#L79-L85&quot;&gt;&lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;lines 79–85&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;These are close to the events I accessed through Selenium’s Chrome performance log in the previous article.&lt;/p&gt;

&lt;p&gt;The difference is not that Playwright sees an entirely different network or anything like that. It consumes the browser events, handles their ordering and edge cases, and converts them into its own internal model.&lt;/p&gt;

&lt;h2 id=&quot;article-xjFtekvhzHVua7p_q2CJz_TP4Us-cdp-does-not-deliver-one-tidy-request-object&quot;&gt;CDP does not deliver one tidy request object&lt;/h2&gt;

&lt;p&gt;It would be convenient if Chromium emitted one event containing a complete request, followed by another containing a complete response. It does not.&lt;/p&gt;

&lt;p&gt;Request and response information can arrive through several protocol events. When interception is enabled, Playwright may need to correlate &lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;Fetch.requestPaused&lt;/code&gt; with &lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;Network.requestWillBeSent&lt;/code&gt;. Redirects alter request relationships. Service workers can cause expected events to be absent. Additional request and response headers arrive through separate events.&lt;/p&gt;

&lt;p&gt;One awkward case appears in &lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;_onRequestPaused&lt;/code&gt;:&lt;/p&gt;

&lt;div&gt;&lt;div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;if&lt;/span&gt; &lt;span&gt;(&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;event&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;networkId&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;// Fetch without networkId means that request was not recognized by inspector, and&lt;/span&gt;
  &lt;span&gt;// it will never receive Network.requestWillBeSent. Continue the request to not affect it.&lt;/span&gt;
  &lt;span&gt;sessionInfo&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;session&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;_sendMayFail&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;Fetch.continueRequest&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;{&lt;/span&gt; &lt;span&gt;requestId&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;event&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;requestId&lt;/span&gt; &lt;span&gt;});&lt;/span&gt;
  &lt;span&gt;return&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;span&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;See &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://github.com/microsoft/playwright/blob/ad18048db947ca0a47c7fa59b77718e3a06afafe/packages/playwright-core/src/server/chromium/crNetworkManager.ts#L245-L249&quot;&gt;&lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;crNetworkManager.ts&lt;/code&gt;, lines 245–249&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Playwright cannot wait to correlate that paused request with &lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;Network.requestWillBeSent&lt;/code&gt;, because the source says the event will never arrive. It continues the request instead.&lt;/p&gt;

&lt;p&gt;There is another special case for service workers. In &lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;_onResponseReceived&lt;/code&gt;, Playwright notes that frame-level requests handled by a service worker may never produce a &lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;requestPaused&lt;/code&gt; event. It may therefore construct the request when the response arrives. See &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://github.com/microsoft/playwright/blob/ad18048db947ca0a47c7fa59b77718e3a06afafe/packages/playwright-core/src/server/chromium/crNetworkManager.ts#L451-L453&quot;&gt;&lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;crNetworkManager.ts&lt;/code&gt;, lines 451–453&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Header information has its own ordering problem. The source comment for &lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;ResponseExtraInfoTracker&lt;/code&gt; says the ordinary request and response events, and their corresponding &lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;ExtraInfo&lt;/code&gt; events, are dispatched through different unassociated channels and may arrive in any order. The tracker associates them so that the extra headers are reliably available by &lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;requestfinished&lt;/code&gt;. See &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://github.com/microsoft/playwright/blob/ad18048db947ca0a47c7fa59b77718e3a06afafe/packages/playwright-core/src/server/chromium/crNetworkManager.ts#L769-L782&quot;&gt;&lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;crNetworkManager.ts&lt;/code&gt;, lines 769–782&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As you can probably gather, there are loads of edge cases like this. Handling them is not glamorous work, but it is a large part of why the public API feels simple compared with working directly against the protocol.&lt;/p&gt;

&lt;h2 id=&quot;article-xjFtekvhzHVua7p_q2CJz_TP4Us-turning-protocol-events-into-playwright-events&quot;&gt;Turning protocol events into Playwright events&lt;/h2&gt;

&lt;p&gt;Once Chromium’s network events have been associated with a Playwright request, they pass into the page’s &lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;FrameManager&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The request path marks the request as in flight, associates document requests with pending navigation, and emits the public request event:&lt;/p&gt;

&lt;div&gt;&lt;div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;requestStarted&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;network&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Request&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;route&lt;/span&gt;&lt;span&gt;?:&lt;/span&gt; &lt;span&gt;network&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;RouteDelegate&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;const&lt;/span&gt; &lt;span&gt;frame&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;request&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;frame&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;
  &lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;_inflightRequestStarted&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;
  &lt;span&gt;if&lt;/span&gt; &lt;span&gt;(&lt;/span&gt;&lt;span&gt;frame&lt;/span&gt; &lt;span&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span&gt;request&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;_documentId&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
    &lt;span&gt;frame&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;_setPendingDocument&lt;/span&gt;&lt;span&gt;({&lt;/span&gt; &lt;span&gt;documentId&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;request&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;_documentId&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;request&lt;/span&gt; &lt;span&gt;});&lt;/span&gt;
  &lt;span&gt;// ...&lt;/span&gt;
  &lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;_page&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;addNetworkRequest&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;
  &lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;_page&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;emitOnContext&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BrowserContext&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Request&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;request&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;
  &lt;span&gt;// ...&lt;/span&gt;
&lt;span&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That code is in &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://github.com/microsoft/playwright/blob/ad18048db947ca0a47c7fa59b77718e3a06afafe/packages/playwright-core/src/server/frames.ts#L329-L343&quot;&gt;&lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;frames.ts&lt;/code&gt;, lines 329–343&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Responses and completion events are emitted nearby:&lt;/p&gt;

&lt;div&gt;&lt;div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;requestReceivedResponse&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;response&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;network&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Response&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;if&lt;/span&gt; &lt;span&gt;(&lt;/span&gt;&lt;span&gt;response&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;_isFavicon&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
    &lt;span&gt;return&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
  &lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;_page&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;emitOnContext&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BrowserContext&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Response&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;response&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;
&lt;span&gt;}&lt;/span&gt;

&lt;span&gt;reportRequestFinished&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;network&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Request&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;response&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;network&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Response&lt;/span&gt; &lt;span&gt;|&lt;/span&gt; &lt;span&gt;null&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;_inflightRequestFinished&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;
  &lt;span&gt;if&lt;/span&gt; &lt;span&gt;(&lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;_isFavicon&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
    &lt;span&gt;return&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
  &lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;_page&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;emitOnContext&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BrowserContext&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;RequestFinished&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;{&lt;/span&gt; &lt;span&gt;request&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;response&lt;/span&gt; &lt;span&gt;});&lt;/span&gt;
&lt;span&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The implementations, including request failure handling, are in &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://github.com/microsoft/playwright/blob/ad18048db947ca0a47c7fa59b77718e3a06afafe/packages/playwright-core/src/server/frames.ts#L345-L356&quot;&gt;&lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;frames.ts&lt;/code&gt;, lines 345–356&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is how low-level CDP events become the public interface used by tests:&lt;/p&gt;

&lt;div&gt;&lt;div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;page&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;on&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;request&lt;/span&gt; &lt;span&gt;=&amp;gt;&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;method&lt;/span&gt;&lt;span&gt;(),&lt;/span&gt; &lt;span&gt;request&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;
&lt;span&gt;});&lt;/span&gt;

&lt;span&gt;page&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;on&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;response&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;response&lt;/span&gt; &lt;span&gt;=&amp;gt;&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;response&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;status&lt;/span&gt;&lt;span&gt;(),&lt;/span&gt; &lt;span&gt;response&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;
&lt;span&gt;});&lt;/span&gt;

&lt;span&gt;page&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;on&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;requestfinished&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;request&lt;/span&gt; &lt;span&gt;=&amp;gt;&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;finished&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;request&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;
&lt;span&gt;});&lt;/span&gt;

&lt;span&gt;page&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;on&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;requestfailed&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;request&lt;/span&gt; &lt;span&gt;=&amp;gt;&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;failed&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;request&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;
&lt;span&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;article-xjFtekvhzHVua7p_q2CJz_TP4Us-how-playwright-implements-networkidle&quot;&gt;How Playwright implements &lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;networkidle&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;The in-flight request tracking lives in &lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;frames.ts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When a request starts, Playwright adds it to the owning frame’s &lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;_inflightRequests&lt;/code&gt; set. If it is the first active request, Playwright stops that frame’s network-idle timer.&lt;/p&gt;

&lt;p&gt;When a request finishes or fails, Playwright removes it. If the set becomes empty, Playwright starts the timer again:&lt;/p&gt;

&lt;div&gt;&lt;div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;private&lt;/span&gt; &lt;span&gt;_inflightRequestFinished&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;network&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Request&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;const&lt;/span&gt; &lt;span&gt;frame&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;request&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;frame&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;
  &lt;span&gt;if&lt;/span&gt; &lt;span&gt;(&lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;_isExcludedFromNetworkIdle&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;||&lt;/span&gt; &lt;span&gt;!&lt;/span&gt;&lt;span&gt;frame&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
    &lt;span&gt;return&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
  &lt;span&gt;if&lt;/span&gt; &lt;span&gt;(&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;frame&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;_inflightRequests&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;has&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;
    &lt;span&gt;return&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
  &lt;span&gt;frame&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;_inflightRequests&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;delete&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;
  &lt;span&gt;if&lt;/span&gt; &lt;span&gt;(&lt;/span&gt;&lt;span&gt;frame&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;_inflightRequests&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;size&lt;/span&gt; &lt;span&gt;===&lt;/span&gt; &lt;span&gt;0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
    &lt;span&gt;frame&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;_startNetworkIdleTimer&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;
&lt;span&gt;}&lt;/span&gt;

&lt;span&gt;private&lt;/span&gt; &lt;span&gt;_inflightRequestStarted&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;network&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Request&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;const&lt;/span&gt; &lt;span&gt;frame&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;request&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;frame&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;
  &lt;span&gt;if&lt;/span&gt; &lt;span&gt;(&lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;_isExcludedFromNetworkIdle&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;||&lt;/span&gt; &lt;span&gt;!&lt;/span&gt;&lt;span&gt;frame&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
    &lt;span&gt;return&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
  &lt;span&gt;frame&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;_inflightRequests&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;add&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;
  &lt;span&gt;if&lt;/span&gt; &lt;span&gt;(&lt;/span&gt;&lt;span&gt;frame&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;_inflightRequests&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;size&lt;/span&gt; &lt;span&gt;===&lt;/span&gt; &lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
    &lt;span&gt;frame&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;_stopNetworkIdleTimer&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;
&lt;span&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The source is in &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://github.com/microsoft/playwright/blob/ad18048db947ca0a47c7fa59b77718e3a06afafe/packages/playwright-core/src/server/frames.ts#L385-L403&quot;&gt;&lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;frames.ts&lt;/code&gt;, lines 385–403&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The implementation deliberately excludes favicons and EventSource connections:&lt;/p&gt;

&lt;div&gt;&lt;div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;private&lt;/span&gt; &lt;span&gt;_isExcludedFromNetworkIdle&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;network&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Request&lt;/span&gt;&lt;span&gt;):&lt;/span&gt; &lt;span&gt;boolean&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;if&lt;/span&gt; &lt;span&gt;(&lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;_isFavicon&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
    &lt;span&gt;return&lt;/span&gt; &lt;span&gt;true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
  &lt;span&gt;if&lt;/span&gt; &lt;span&gt;(&lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;resourceType&lt;/span&gt;&lt;span&gt;()&lt;/span&gt; &lt;span&gt;===&lt;/span&gt; &lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;eventsource&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
    &lt;span&gt;return&lt;/span&gt; &lt;span&gt;true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
  &lt;span&gt;return&lt;/span&gt; &lt;span&gt;false&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;span&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;See &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://github.com/microsoft/playwright/blob/ad18048db947ca0a47c7fa59b77718e3a06afafe/packages/playwright-core/src/server/frames.ts#L405-L411&quot;&gt;&lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;frames.ts&lt;/code&gt;, lines 405–411&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A favicon is browser housekeeping rather than meaningful application activity. An EventSource connection is long-lived by design, so counting it would prevent pages using server-sent events from ever reaching network idle.&lt;/p&gt;

&lt;p&gt;The idle state is also calculated through the frame tree (the main page and its nested iframes). Lifecycle state is recorded on frames, and clearing lifecycle state resets the timer around the remaining current-navigation request. The relevant lifecycle and reset handling can be followed in &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://github.com/microsoft/playwright/blob/ad18048db947ca0a47c7fa59b77718e3a06afafe/packages/playwright-core/src/server/frames.ts#L573-L584&quot;&gt;&lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;frames.ts&lt;/code&gt;, lines 573–584&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is honestly a more precise than saying Playwright waits until there are no requests. A closer description may be that Playwright tracks in-flight requests per frame, starts an idle timer when a frame’s set becomes empty, and combines the resulting state through the frame hierarchy.&lt;/p&gt;

&lt;p&gt;It also shows why &lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;networkidle&lt;/code&gt; is not a universal indication that an application is ready.&lt;/p&gt;

&lt;p&gt;A quiet network tells us nothing about a CSS animation, a client-side timer, data already queued for rendering, or an application bug that prevented the expected request from starting.&lt;/p&gt;

&lt;h2 id=&quot;article-xjFtekvhzHVua7p_q2CJz_TP4Us-how-the-click-starts-waiting-before-navigation-happens&quot;&gt;How the click starts waiting before navigation happens&lt;/h2&gt;

&lt;p&gt;There is another race to solve.&lt;/p&gt;

&lt;p&gt;Suppose Playwright dispatched a click and only then began listening for navigation. A sufficiently fast navigation could start before the listener was installed.&lt;/p&gt;

&lt;p&gt;The pointer action avoids that race by running the input inside &lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;waitForSignalsCreatedBy&lt;/code&gt;:&lt;/p&gt;

&lt;div&gt;&lt;div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;async&lt;/span&gt; &lt;span&gt;waitForSignalsCreatedBy&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;T&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;
  &lt;span&gt;progress&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;Progress&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;waitAfter&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;boolean&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
  &lt;span&gt;action&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;(&lt;/span&gt;&lt;span&gt;progress&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;Progress&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;=&amp;gt;&lt;/span&gt; &lt;span&gt;Promise&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;T&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;
&lt;span&gt;):&lt;/span&gt; &lt;span&gt;Promise&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;T&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
  &lt;span&gt;if&lt;/span&gt; &lt;span&gt;(&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;waitAfter&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
    &lt;span&gt;return&lt;/span&gt; &lt;span&gt;action&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;progress&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;
  &lt;span&gt;const&lt;/span&gt; &lt;span&gt;barrier&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;new&lt;/span&gt; &lt;span&gt;SignalBarrier&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;progress&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;
  &lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;_signalBarriers&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;add&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;barrier&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;
  &lt;span&gt;try&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
    &lt;span&gt;const&lt;/span&gt; &lt;span&gt;result&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;await&lt;/span&gt; &lt;span&gt;action&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;progress&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;
    &lt;span&gt;await&lt;/span&gt; &lt;span&gt;progress&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;race&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;_page&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;delegate&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;inputActionEpilogue&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;
    &lt;span&gt;await&lt;/span&gt; &lt;span&gt;barrier&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;waitFor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;progress&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;
    &lt;span&gt;// Resolve in the next task, after all waitForNavigations.&lt;/span&gt;
    &lt;span&gt;await&lt;/span&gt; &lt;span&gt;new&lt;/span&gt; &lt;span&gt;Promise&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;makeWaitForNextTask&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;
    &lt;span&gt;return&lt;/span&gt; &lt;span&gt;result&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
  &lt;span&gt;}&lt;/span&gt; &lt;span&gt;finally&lt;/span&gt; &lt;span&gt;{&lt;/span&gt;
    &lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;_signalBarriers&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;delete&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;barrier&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;
  &lt;span&gt;}&lt;/span&gt;
&lt;span&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That method is in &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://github.com/microsoft/playwright/blob/ad18048db947ca0a47c7fa59b77718e3a06afafe/packages/playwright-core/src/server/frames.ts#L192-L207&quot;&gt;&lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;frames.ts&lt;/code&gt;, lines 192–207&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;SignalBarrier&lt;/code&gt; acts as a gate. It keeps the action open until navigation initiated by the click has been acknowledged.&lt;/p&gt;

&lt;p&gt;When a frame may request navigation, active ‘barriers’ are retained. When the possible request has been resolved, they are released. If a frame actually requests navigation, Playwright adds that frame navigation to the barrier. See &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://github.com/microsoft/playwright/blob/ad18048db947ca0a47c7fa59b77718e3a06afafe/packages/playwright-core/src/server/frames.ts#L169-L189&quot;&gt;&lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;frames.ts&lt;/code&gt;, lines 169–189&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The barrier is not a general wait for every network request caused by the click. It coordinates browser signals created by the action, especially navigation. General network observation continues through the network manager and the public request events.&lt;/p&gt;

&lt;p&gt;A click may trigger an API request without navigating. Playwright cannot safely infer which arbitrary response represents the business operation a test cares about. The test must express that relationship explicitly:&lt;/p&gt;

&lt;div&gt;&lt;div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;const&lt;/span&gt; &lt;span&gt;responsePromise&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;page&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;waitForResponse&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;
  &lt;span&gt;response&lt;/span&gt; &lt;span&gt;=&amp;gt;&lt;/span&gt;
    &lt;span&gt;response&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;endsWith&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;/orders&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span&gt;response&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;method&lt;/span&gt;&lt;span&gt;()&lt;/span&gt; &lt;span&gt;===&lt;/span&gt; &lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;POST&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;
&lt;span&gt;);&lt;/span&gt;

&lt;span&gt;await&lt;/span&gt; &lt;span&gt;page&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getByRole&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;button&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;{&lt;/span&gt; &lt;span&gt;name&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;Submit&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt; &lt;span&gt;}).&lt;/span&gt;&lt;span&gt;click&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;

&lt;span&gt;const&lt;/span&gt; &lt;span&gt;response&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;await&lt;/span&gt; &lt;span&gt;responsePromise&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The response wait is created before the click for the same reason as the internal barrier: a fast event must not be missed.&lt;/p&gt;

&lt;p&gt;This is why Playwright’s documentation tells us to set up &lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;waitForResponse&lt;/code&gt; before the action that triggers it. The test applies the same broad principle Playwright uses internally with &lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;waitForSignalsCreatedBy&lt;/code&gt;: install the listener first, then perform the action.&lt;/p&gt;

&lt;h2 id=&quot;article-xjFtekvhzHVua7p_q2CJz_TP4Us-connecting-this-back-to-selenium&quot;&gt;Connecting this back to Selenium&lt;/h2&gt;

&lt;p&gt;Following the source changes how I would describe my previous experiment, but it does not make the experiment wrong.&lt;/p&gt;

&lt;p&gt;The Chrome performance log approach observed real CDP network events. Playwright’s Chromium network manager listens to the same family of events.&lt;/p&gt;

&lt;p&gt;What Playwright adds is a huge coordination layer. It installs protocol listeners, correlates Fetch- and Network-domain events, handles redirects and service workers, constructs request and response objects, exposes them as public events, tracks requests per frame, calculates network idle, and associates page-loading requests with navigation.&lt;/p&gt;

&lt;p&gt;My Selenium examples addressed a narrower problem: determine whether network activity appeared to be in progress.&lt;/p&gt;

&lt;p&gt;That may be enough for a particular test suite. Playwright needs a heavier implementation because a reusable framework must handle a broader range of browser behaviour, test styles, and edge cases than an application-specific helper.&lt;/p&gt;

&lt;p&gt;A network counter also does not address the first half of the problem.&lt;/p&gt;

&lt;p&gt;Before a request or navigation can exist, Playwright still has to make the click happen. That requires locator resolution, element-state checks, scrolling, geometry, hit testing, and browser input.&lt;/p&gt;

&lt;p&gt;Network awareness cannot tell us that a transparent overlay is blocking a click. Pre-click actionability checks cannot tell us that the expected API response returned the correct data.&lt;/p&gt;

&lt;p&gt;They solve different parts of synchronisation.&lt;/p&gt;

&lt;h2 id=&quot;article-xjFtekvhzHVua7p_q2CJz_TP4Us-wrapping-up&quot;&gt;Wrapping up&lt;/h2&gt;

&lt;p&gt;We began with one line:&lt;/p&gt;

&lt;div&gt;&lt;div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;await&lt;/span&gt; &lt;span&gt;page&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getByRole&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;button&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;{&lt;/span&gt; &lt;span&gt;name&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;apos;&lt;/span&gt;&lt;span&gt;Submit&lt;/span&gt;&lt;span&gt;&amp;apos;&lt;/span&gt; &lt;span&gt;}).&lt;/span&gt;&lt;span&gt;click&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Following it through the source reveals two connected systems.&lt;/p&gt;

&lt;p&gt;The first prepares and dispatches the input:&lt;/p&gt;

&lt;div&gt;&lt;div&gt;&lt;pre&gt;&lt;code&gt;resolve the locator
check visible, enabled and stable
scroll the element
calculate a point
check the hit target
dispatch browser input
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The second observes what the browser does next:&lt;/p&gt;

&lt;div&gt;&lt;div&gt;&lt;pre&gt;&lt;code&gt;receive raw request and response events from the browser
normalise them into Playwright&amp;apos;s own objects
track which requests are still in progress
emit public events that tests can observe
associate page-loading requests with navigation
wait for navigation triggered by the action
calculate network-idle state across the page and its iframes
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;These are the browser and network signals I was trying to expose through Selenium in the previous article. Playwright uses the same underlying family of events, but it does considerably more than count requests.&lt;/p&gt;

&lt;p&gt;CDP is noisy and sometimes incomplete. Related information arrives through separate events and in inconvenient orders. Requests may redirect, pass through service workers, come from cache, or fail before every expected event appears. Playwright contains the code required to turn that stream into a more stable model.&lt;/p&gt;

&lt;p&gt;The implementation also shows why &lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;networkidle&lt;/code&gt; is only one possible signal. It represents a quiet period in which no tracked requests are active. It does not establish that the application is correct, useful, or ready for the next business-level assertion.&lt;/p&gt;

&lt;p&gt;I still do not think the conclusion is simply to choose Playwright over Selenium.&lt;/p&gt;

&lt;p&gt;Selenium users can observe CDP events, execute browser-side JavaScript, and build application-specific waits. Playwright has chosen to make more of that coordination part of the framework itself. How much you want buried under an interface is up to you.&lt;/p&gt;

&lt;p&gt;The useful lesson is to be precise about what we are waiting for.&lt;/p&gt;

&lt;p&gt;Before a click, that may be a stable, enabled, and unobstructed target. After it, that may be a navigation lifecycle event or one specific API response. Sometimes network idle is useful. Sometimes it is the wrong question entirely.&lt;/p&gt;

&lt;p&gt;I may still try reproducing Playwright’s “is something blocking the click?” check in Selenium.&lt;/p&gt;

&lt;p&gt;I will not be reproducing &lt;code class=&quot;language-plaintext language-highlighter-rouge&quot;&gt;crNetworkManager&lt;/code&gt;. Life is too short!&lt;/p&gt;

&lt;p&gt;Did I get something wrong? Have you followed a similar trail through Playwright or Selenium? Please get in touch at &lt;a href=&quot;mailto:joseph@josephward.tech&quot;&gt;joseph@josephward.tech&lt;/a&gt;.&lt;/p&gt;</summary><author><name>Joseph Ward</name></author><source gr:stream-id="feed/https://josephward.tech/feed.xml"><id>tag:google.com,2005:reader/feed/https://josephward.tech/feed.xml</id><title type="html">Joseph Ward</title><link rel="alternate" href="https://josephward.tech/" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1783376822000"><id gr:original-id="https://medium.com/p/9f279ee6678c">tag:google.com,2005:reader/item/000008a600000024</id><category term="prompt-management"></category><category term="ai-monsoon"></category><category term="prompt-engineering"></category><category term="writing-prompts"></category><category term="claude"></category><title type="html">We Have a Name for It. We Just Don’t Treat It Like It Matters.</title><published>2026-07-06T22:27:02Z</published><updated>2026-07-06T22:27:02Z</updated><link rel="alternate" href="https://sajithatharaka.medium.com/we-have-a-name-for-it-we-just-dont-treat-it-like-it-matters-9f279ee6678c?source=rss-3af8e7cc568a------2" type="text/html"></link><summary type="html">&lt;div&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://sajithatharaka.medium.com/we-have-a-name-for-it-we-just-dont-treat-it-like-it-matters-9f279ee6678c?source=rss-3af8e7cc568a------2&quot;&gt;&lt;img class=&quot;bqrUnknownImgSize&quot; src=&quot;https://cdn-images-1.medium.com/max/1536/1*WFnbXjk6AXKVSfdDR01Iyw.png&quot; width=&quot;1536&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Why your .claude folder is quietly telling you how you actually think&lt;/p&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://sajithatharaka.medium.com/we-have-a-name-for-it-we-just-dont-treat-it-like-it-matters-9f279ee6678c?source=rss-3af8e7cc568a------2&quot;&gt;Continue reading on Medium »&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;</summary><author><name>Sajitha Pathirana</name></author><source gr:stream-id="feed/https://medium.com/feed/@sajithatharaka"><id>tag:google.com,2005:reader/feed/https://medium.com/feed/@sajithatharaka</id><title type="html">Stories by Sajitha Pathirana on Medium</title><link rel="alternate" href="https://medium.com/@sajithatharaka?source=rss-3af8e7cc568a------2" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1783375200000"><id gr:original-id="https://scrolltest.com/?p=7395">tag:google.com,2005:reader/item/0000044400000285</id><category term="Test Automation"></category><category term="Testing"></category><title type="html">Smart Automation Testing Strategies: Why Your Passing Tests Miss Production Bugs</title><published>2026-07-06T22:00:00Z</published><updated>2026-07-06T22:00:00Z</updated><link rel="alternate" href="https://scrolltest.com/smart-automation-beyond-happy-path-production-bugs/" type="text/html"></link><summary type="html">&lt;p&gt;All tests passing. Then production broke. Why happy-path automation creates false confidence. The 4 pillars of smart automation that actually catch real bugs.&lt;/p&gt;
&lt;p&gt;The post &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; rel=&quot;nofollow&quot; href=&quot;https://scrolltest.com/smart-automation-beyond-happy-path-production-bugs/&quot;&gt;Smart Automation Testing Strategies: Why Your Passing Tests Miss Production Bugs&lt;/a&gt; appeared first on &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; rel=&quot;nofollow&quot; href=&quot;https://scrolltest.com&quot;&gt;Software Testing &amp;amp; Automation&lt;/a&gt;.&lt;/p&gt;</summary><author><name>Pramod Dutta</name></author><source gr:stream-id="feed/https://scrolltest.com/feed/"><id>tag:google.com,2005:reader/feed/https://scrolltest.com/feed/</id><title type="html">Software Testing &amp; Automation</title><link rel="alternate" href="https://scrolltest.com" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1783372708000"><id gr:original-id="6a4c07808cfabc0001b954fd">tag:google.com,2005:reader/item/00000a7d00000016</id><category term="Personal"></category><category term="Backup"></category><title type="html">My laptop died last week, and here is what it took with it</title><published>2026-07-06T21:18:28Z</published><updated>2026-07-06T21:18:28Z</updated><link rel="alternate" href="https://alexzh.com/laptop-backup-system/" type="text/html"></link><summary type="html">&lt;img class=&quot;bqrUnknownImgSize&quot; src=&quot;https://storage.ghost.io/c/04/b5/04b572f2-2503-428f-b73c-45f0e4a6046e/content/images/2026/07/laptop-backup-system.png&quot; alt=&quot;My laptop died last week, and here is what it took with it&quot;&gt;&lt;p&gt;A few days ago, I accidentally spilled water on my laptop.&lt;/p&gt;&lt;p&gt;It restarted a few times and turned off entirely.&lt;/p&gt;&lt;p&gt;I did everything the internet told me to. Dried it out and didn&amp;apos;t touch the power button.&lt;/p&gt;&lt;p&gt;Every repair shop was already closed. So I waited overnight, not knowing if anything on that laptop was still alive.&lt;/p&gt;&lt;p&gt;The next morning, the guy at the shop checked it and said: &amp;quot;The chances of recovery are small. Do you want us to try?&amp;quot;&lt;/p&gt;&lt;p&gt;Until that moment, I had hope. It was just water, not coffee, not something sticky.&lt;/p&gt;&lt;p&gt;But now, all I could focus on was what hadn&amp;apos;t been backed up:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;My photos&lt;/li&gt;&lt;li&gt;The fixes for the next release of my book&lt;/li&gt;&lt;li&gt;The code for one of my personal projects&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Gone. Maybe forever.&lt;/p&gt;&lt;p&gt;Now let me ask you something.&lt;/p&gt;&lt;p&gt;If your laptop died right now, without any warning, what would you lose?&lt;/p&gt;&lt;p&gt;Do you actually back up the things you can&amp;apos;t replace?&lt;/p&gt;&lt;p&gt;If you just pictured something you wouldn&amp;apos;t want to lose, you’re exactly where I was a week ago. Here’s the simple system I wish I’d had back then:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Start with what you can&amp;apos;t replace.&lt;/li&gt;&lt;li&gt;Automate a backup process. A backup you have to remember is a backup you&amp;apos;ll forget.&lt;/li&gt;&lt;li&gt;Follow the 3-2-1 rule: 3 copies of your data (the original included) on 2 different types of storage with 1 copy somewhere remote.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;If I&amp;apos;d followed step 2, the changes that I made last week for my book would be safe right now.&lt;/p&gt;&lt;p&gt;So here&amp;apos;s what I&amp;apos;d suggest. &lt;/p&gt;&lt;p&gt;Tonight, before you close your laptop, pick the one folder you wouldn&amp;apos;t want to lose, and copy it somewhere else: cloud, USB drive, anywhere.&lt;/p&gt;&lt;p&gt;That&amp;apos;s it. Five minutes. You can build the full 3-2-1 setup this weekend. But tonight, get your irreplaceable stuff to two places instead of one.&lt;/p&gt;&lt;p&gt;Take care of your data (and your drinks near your laptop),&lt;/p&gt;&lt;p&gt;Alex&lt;/p&gt;&lt;hr&gt;&lt;p&gt;&lt;strong&gt;P.S.&lt;/strong&gt; I&amp;apos;m writing this from a new laptop.&lt;/p&gt;&lt;p&gt;The repair shop called me back a few days later. They gave me the old one and said there was nothing they could do.&lt;/p&gt;&lt;p&gt;I&amp;apos;m telling you this because &amp;quot;I&amp;apos;ll back it up later&amp;quot; was working fine for me too, right until the moment it wasn&amp;apos;t.&lt;/p&gt;</summary><author><name>Alex Zhukovich</name></author><source gr:stream-id="feed/https://alexzh.com/rss/"><id>tag:google.com,2005:reader/feed/https://alexzh.com/rss/</id><title type="html">Mobile development with Alex</title><link rel="alternate" href="https://alexzh.com/" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1783351742000"><id gr:original-id="https://angryweasel.substack.com/p/what-the-keeper-or-leader-knows">tag:google.com,2005:reader/item/00000ad70000006a</id><title type="html">What the Keeper (or Leader) Knows</title><published>2026-07-06T15:29:02Z</published><updated>2026-07-06T15:29:02Z</updated><link rel="alternate" href="https://angryweasel.substack.com/p/what-the-keeper-or-leader-knows" type="text/html"></link><summary type="html">&lt;p&gt;I’m not much of a sports-watching person, with one big exception. I watch a lot of non-American football (aka Soccer) - and right now, the whole world is watching the World Cup matches.&lt;/p&gt;&lt;p&gt;I grew up playing a lot of soccer. I stopped playing when I got my first grownup job, but found my way onto pretty good adult teams for a while later in life. I was a midfielder. I liked to run a lot, and I could find space between and around people, and I could make good passes. I understood the game pretty well from that perspective. I knew positioning, my role, and where the players were around me. Then one season I volunteered to play keeper, and I got a new perspective.&lt;/p&gt;&lt;p&gt;Once I got over the pressure of being the last defender with fast and strong people running at me full speed, I began to notice the view. Standing in goal, I could see the entire field in front of me. I could see the shape of both teams, where the gaps were forming, who was out of position, and where the pressure was building before anyone else felt it. I could see things that the players in the middle of the action usually couldn’t see from where they were standing. It’s a role made for people who like observing and thinking.&lt;/p&gt;&lt;p&gt;The other thing I noticed was that seeing wasn’t enough. I had to talk.&lt;/p&gt;&lt;h3&gt;The Keeper Never Stops Talking&lt;/h3&gt;&lt;p&gt;Watch a goalkeeper closely the next time you see a match, and look beyond the saves. They’re constantly communicating with their teammates. They organize the defense, they warn defenders about a runner sneaking in from behind, or they tell the team to push up or drop back. A good keeper is a constant stream of information, and most people watching probably don’t even notice it.&lt;/p&gt;&lt;p&gt;I found that observation, combined with better communication meant fewer shots. And, even though I may not have been so great at stopping shots, I found that I could prevent a lot of shots from ever happening just by telling people what I was seeing.&lt;/p&gt;&lt;p&gt;The team didn’t need me to make big plays. They needed me to give them information they couldn’t get from where they were playing.&lt;/p&gt;&lt;h3&gt;Enough About Sports&lt;/h3&gt;&lt;p&gt;When you move into a leadership role, something similar happens to your view.&lt;/p&gt;&lt;p&gt;You’re not the middle of the action the way you used to be. You’re not writing the code, running the project, or doing the work directly. And for a lot of leaders, that loss of direct contribution feels uncomfortable at first. It can feel like you’re less useful than you used to be.&lt;/p&gt;&lt;p&gt;But your view has changed in the same way mine did when I moved to keeper. You can see the shape of the whole system now. You’re in meetings that your team isn’t in. You have context they don’t have. You can see the pressure building from a direction they probably haven’t noticed yet. You can see the gap forming before anyone else feels it.&lt;/p&gt;&lt;p&gt;The question is whether you’re paying attention and communicating.&lt;/p&gt;&lt;p&gt;A lot of senior leaders hoard information without realizing they’re doing it. They may feel like sharing everything is inefficient, or they assume their team already knows, or  they’re just so focused on their own decisions that they forget their team is playing the game without the view from the back of the field.&lt;/p&gt;&lt;p&gt;What your team experiences is the equivalent of a goalkeeper who sees an attacker making a run and says nothing. The defender gets beaten because the information that would have helped them was right there and never got shared.&lt;/p&gt;&lt;p&gt;I once worked with a leader who came back from a quarterly business review with a head full of context about where the company was heading. They had more context on the competition, some ideas on leadership changes, some early signals about where investment was going next year. Nothing was urgent, so they didn’t mention any of it to their team.&lt;/p&gt;&lt;p&gt;A few weeks later, one of their senior engineers proposed a significant technical investment that made complete sense given everything the team could see. The leader shot it down quickly. From the team’s perspective, it came out of nowhere. The proposal was solid, and the reasoning was sound. Why would you say no to this? Morale suffered, and people were frustrated.&lt;/p&gt;&lt;p&gt;The leader had context that made the answer obvious. The team had none of it. What felt like a clear decision from their view looked like an arbitrary one from the middle.&lt;/p&gt;&lt;h3&gt;What Talking Actually Looks Like&lt;/h3&gt;&lt;p&gt;I’m not suggesting over-communicating or holding endless update meetings. It’s about developing the habit of asking yourself what you can see that your team can’t, and then finding the right way to share it.&lt;/p&gt;&lt;p&gt;Sometimes that’s context about a decision that came from above. Sometimes it’s information you’re picking up from another part of the organization that might affect your team’s priorities. Sometimes it’s just telling someone that their work is being noticed by people they’ll never meet, because you were in the meeting when it came up and they weren’t.&lt;/p&gt;&lt;p&gt;None of that is complicated, but all of it requires you to be deliberate about it, because the natural pull is to stay focused on your own decisions and assume the rest will take care of itself. The habit isn&amp;apos;t complicated, but it&amp;apos;s easy to forget, at work as well as with the people you care about.&lt;/p&gt;&lt;p&gt;The best leaders I’ve worked with had this habit deeply ingrained. They shared information generously. They told you what they were seeing, what they were hearing, and what was coming. They treated their team’s situational awareness as part of their own job, not as a nice-to-have.&lt;/p&gt;&lt;p&gt;I’ve found that a lot of information feels secret, but isn’t secret at all. It’s just not shared. &lt;/p&gt;&lt;p&gt;One of my biggest leadership principles is &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://angryweasel.substack.com/p/working-in-the-open&quot;&gt;Transparency&lt;/a&gt;. It makes a big difference when your team feels like they know what’s going on.&lt;/p&gt;&lt;h3&gt;Watch It&lt;/h3&gt;&lt;p&gt;The World Cup will be over in a few weeks. But the next time you watch a match, spend a few minutes watching the keeper instead of the ball. Watch how much they talk. Watch how much of the game they’re running from the back of the field.&lt;/p&gt;&lt;p&gt;At every level, in every organization, the person with the best view has a responsibility to share it.&lt;/p&gt;&lt;div&gt;&lt;hr&gt;&lt;/div&gt;&lt;p&gt;If you’re not sure your team is getting the view from where you’re standing, that’s worth thinking about. And if you’d like to think through it together, &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://tidycal.com/19xqg4y/introductory-call-free&quot;&gt;I’d love to talk&lt;/a&gt;.&lt;/p&gt;&lt;p style=&quot;clear: both&quot;&gt;&lt;/p&gt;&lt;p data-bqr-info=&quot;attachment&quot;&gt;&lt;img class=&quot;bqrUnknownImgSize&quot; src=&quot;https://substack-post-media.s3.amazonaws.com/public/images/625f8136-02fc-4ed8-89c7-704ebca50913_1254x1254.png&quot;&gt;&lt;/p&gt;</summary><author><name>Alan Page</name></author><source gr:stream-id="feed/https://angryweasel.substack.com/feed"><id>tag:google.com,2005:reader/feed/https://angryweasel.substack.com/feed</id><title type="html">The Weasel Speaks</title><link rel="alternate" href="https://angryweasel.substack.com" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1783347810000"><id gr:original-id="https://medium.com/p/308b0a8a9fc7">tag:google.com,2005:reader/item/000003600000001e</id><category term="platform-engineering"></category><category term="valkey"></category><category term="redis"></category><category term="blog"></category><title type="html">How we switched 150 stores from Redis to Valkey, and nobody cared!</title><published>2026-07-06T14:23:30Z</published><updated>2026-07-06T14:23:30Z</updated><link rel="alternate" href="https://medium.com/wehkamp-techblog/how-we-switched-150-stores-from-redis-to-valkey-and-nobody-cared-308b0a8a9fc7?source=rss----a3c49d1b884---4" type="text/html"></link><summary type="html">&lt;figure&gt;&lt;img class=&quot;bqrUnknownImgSize&quot; alt src=&quot;https://cdn-images-1.medium.com/max/1024/0*BSeRgA8td2tweeRm.jpg&quot;&gt;&lt;/figure&gt;&lt;p&gt;Ever since we started our move from the on-premises data center to the cloud, delivery teams haven’t had to worry about their infrastructure. We’ve built a platform that lets delivery teams focus on solving business problems. At Wehkamp, teams don’t have to worry about Kubernetes, network infrastructure, or writing Terraform code to provision data stores. They don’t even need to know about AWS! Team infrastructure is easily provisioned through our Slack bot. &lt;em&gt;Basically, the teams have been running serverless since 2013!&lt;/em&gt;&lt;/p&gt;&lt;p&gt;Having such a platform comes with a peculiar downside: when teams don’t &lt;em&gt;have to care&lt;/em&gt; about infrastructure, they usually… don’t!&lt;/p&gt;&lt;p&gt;&lt;em&gt;So what if we want to migrate our AWS ElastiCache Redis stores to Valkey?&lt;/em&gt; In this article we’ll explain how we switched 150+ AWS ElastiCache stores from Redis to Valkey.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;A big shout-out to &lt;/strong&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.linkedin.com/in/klaastalsma/&quot;&gt;&lt;strong&gt;Klaas Talsma&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt; and &lt;/strong&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.linkedin.com/in/chris-v-4b9a62b/&quot;&gt;&lt;strong&gt;Chris Vahl&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt; for working together on this story. We started this migration at the beginning of 2026, so this article was long overdue.&lt;/strong&gt;&lt;/p&gt;&lt;h3&gt;Why?&lt;/h3&gt;&lt;p&gt;Back in 2024, &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://redis.io/blog/redis-adopts-dual-source-available-licensing/&quot;&gt;Redis switched to another license&lt;/a&gt;, and that got developers around the world thinking about a fork. Valkey was born in no time! &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://aws.amazon.com/blogs/opensource/why-aws-supports-valkey/&quot;&gt;AWS was heavily involved from the start&lt;/a&gt;. Honestly, the results were very impressive. And they didn’t stop there, as Valkey 8.1 was released with &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://aws.amazon.com/blogs/database/year-one-of-valkey-open-source-innovations-and-elasticache-version-8-1-for-valkey/#:~:text=Innovations%20that%20matter&quot;&gt;even more power&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;When we read that it was &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://aws.amazon.com/blogs/database/get-started-with-amazon-elasticache-for-valkey/#:~:text=On%20ElastiCache%20for%20Valkey%20self%2Ddesigned%20(node%2Dbased)%20clusters%2C%20you%20can%20benefit%20from%20up%20to%2020%25%20lower%20cost%20compared%20to%20other%20engines.&quot;&gt;20% cheaper to run Valkey&lt;/a&gt; than Redis, the decision became a no-brainer. So we threw together some slides, gave a Tech Talk, and started adding Valkey to our platform.&lt;/p&gt;&lt;figure&gt;&lt;img class=&quot;bqrUnknownImgSize&quot; alt src=&quot;https://cdn-images-1.medium.com/max/1024/0*VhFMZaiZO98NBAbT.jpg&quot;&gt;&lt;figcaption&gt;This was only the beginning, as these slides are from early 2025.&lt;/figcaption&gt;&lt;/figure&gt;&lt;figure&gt;&lt;img class=&quot;bqrUnknownImgSize&quot; alt src=&quot;https://cdn-images-1.medium.com/max/1024/0*2StIYHKXKzNughu1.png&quot;&gt;&lt;figcaption&gt;To sum up: it is faster &amp;amp;&amp;amp; cheaper =&amp;gt; let’s migrate.&lt;/figcaption&gt;&lt;/figure&gt;&lt;h3&gt;Step 1: Stop the bleeding&lt;/h3&gt;&lt;p&gt;Whenever we introduce new technology, we work according to a two-step principle:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Stop the bleeding: make sure &lt;em&gt;newly&lt;/em&gt; provisioned infrastructure uses the new technology by &lt;em&gt;default&lt;/em&gt;.&lt;/li&gt;&lt;li&gt;Migration: present a migration path and let teams move at their own pace.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Our delivery teams don’t have to write Terraform code (they can); we provide a Slack bot to guide developers to provisioning a data source. Here we swapped out the provisioning of Redis resources for that of Valkey. In the beginning we even kept the Redis icon, but over time that got swapped as well, as the name caused confusion.&lt;/p&gt;&lt;figure&gt;&lt;img class=&quot;bqrUnknownImgSize&quot; alt src=&quot;https://cdn-images-1.medium.com/max/520/0*G-lLy7yN3hCfJbib.png&quot;&gt;&lt;figcaption&gt;The Provisioner provides an easy dialog for Valkey provisioning. In an earlier version you could select Redis or Valkey engines.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;Our Provisioner provisions Valkey according to Tech Hub standards, including TLS, authentication, and multi-AZ. It generates Terraform code, commits to the IAC Git repository, creates a PR, and watches it roll out to production, all while keeping the user informed on Slack.&lt;/p&gt;&lt;h3&gt;Step 2: Migration&lt;/h3&gt;&lt;p&gt;Again, we made some slides:&lt;/p&gt;&lt;figure&gt;&lt;img class=&quot;bqrUnknownImgSize&quot; alt src=&quot;https://cdn-images-1.medium.com/max/1024/0*Wn87-Zq5KAR7Paz3.png&quot;&gt;&lt;figcaption&gt;We made TLS mandatory for our new Valkey setups, which requires application changes.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;The usual suspects moved right away, but the bulk of the teams did not migrate 😱. So we talked to the teams to find out if there were any blockers.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Some older services did not use AUTH or a TLS connection, and the teams did not want to refactor those applications to include both features.&lt;/li&gt;&lt;li&gt;Some teams still had their service on a &lt;em&gt;single fascia&lt;/em&gt; environment, so they needed to move to a multi-fascia environment before they could benefit from the new setup.&lt;/li&gt;&lt;li&gt;Some teams had very busy backlogs, so they couldn’t prioritize it.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Step 3? Now what?&lt;/h3&gt;&lt;p&gt;What could we, as a platform team, do? If we wanted to reap the performance and financial benefits, we needed to make an in-place upgrade possible. Fortunately for us, Valkey is meant as a drop-in replacement.&lt;/p&gt;&lt;p&gt;However, we hit a technical hurdle: our latest infrastructure standards mandate encryption and TLS, but applying those specific enhancements to existing environments would have made an in-place engine upgrade impossible. Fortunately there was a pragmatic solution: we rewrote an older version of the Terraform module, so old environments could also benefit from the new engine.&lt;/p&gt;&lt;p&gt;By testing this extensively on clusters with at least two nodes, we confirmed we could swap the engine under the hood with no downtime, because with a multi-node cluster, there’s always a node left to serve traffic during the switch.&lt;/p&gt;&lt;p&gt;The result was a process so streamlined that teams could migrate to Valkey by updating just a few lines of code:&lt;/p&gt;&lt;figure&gt;&lt;img class=&quot;bqrUnknownImgSize&quot; alt src=&quot;https://cdn-images-1.medium.com/max/1024/0*5xBcZj6sksb9fmA3.png&quot;&gt;&lt;figcaption&gt;Only 4 lines need to be changed.&lt;/figcaption&gt;&lt;/figure&gt;&lt;h3&gt;A New Year’s Resolution&lt;/h3&gt;&lt;p&gt;The next step was to talk to &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.linkedin.com/in/kmroumen/&quot;&gt;Koen Roumen, Head of Technology&lt;/a&gt;. We explained that there was no reason not to move, and we came up with a plan: &lt;em&gt;either&lt;/em&gt; the teams move &lt;em&gt;before&lt;/em&gt; a certain date, or &lt;em&gt;we would make the move for them.&lt;/em&gt; Maybe it was the optimism that comes with starting a new year, or maybe the stars aligned, but we all agreed on a pretty tight timeline.&lt;/p&gt;&lt;figure&gt;&lt;img class=&quot;bqrUnknownImgSize&quot; alt src=&quot;https://cdn-images-1.medium.com/max/1024/0*Jgp1srV_hTa1I11-.png&quot;&gt;&lt;figcaption&gt;We wanted to move within the month.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;Again, some teams woke up and moved, but most teams were like: &lt;em&gt;if you’re sure there is no impact, go for it!&lt;/em&gt; And so we did. We ran the migration in batches. On the morning of the 27th, we migrated a batch of 47 stores for 6 delivery teams across 3 AWS development environments to Valkey. It went incredibly smoothly. Yes, it took AWS a while to provision the stores (no idea why), but by 9 o’clock we were done. Our delivery teams did not report any problems.&lt;/p&gt;&lt;p&gt;Production was scheduled for a week later. As dev went so smoothly, we dropped our requirement to send a backend engineer to the call, and we decided to start at 09:00 instead of 08:00. Again: one smooth transition.&lt;/p&gt;&lt;h3&gt;Step 4: Right sizing&lt;/h3&gt;&lt;p&gt;Now that the migration to Valkey was behind us, we shifted our focus from “making it work” to “making it right”. Because our in-place migration kept the exact same instance types that were previously running Redis, much of our fleet was likely over-provisioned. On a number of stores we &lt;em&gt;observed&lt;/em&gt; lower resource utilization after the switch.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Valkey runs leaner. Where we saw genuinely lower load after the swap, the engine itself is the likely driver.&lt;/li&gt;&lt;li&gt;Some stores were simply oversized under Redis. Safety margins had been chosen years ago and never revisited. That capacity was “ghost capacity” regardless of engine, the migration was just the moment we finally went looking for it.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;To do this well, we started a deep-dive analysis, leveraging LLMs and the AWS CLI to parse two weeks of CloudWatch metrics since the migration. Guided by our FinOps tooling, this data-driven approach identified consistently over-provisioned stores, which we then scaled down, keeping headroom for peaks. It’s a pragmatic approach to cloud spending: optimize the baseline first, so we only pay for the performance we actually use.&lt;/p&gt;&lt;h3&gt;So what did we learn?&lt;/h3&gt;&lt;p&gt;155 stores migrated, no production downtime, and zero complaints. We switched the engine, we’re seeing the savings, and, just as we intended, nobody even noticed. Great.&lt;/p&gt;&lt;p&gt;Our main lessons:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Valkey really is a great replacement for Redis.&lt;/li&gt;&lt;li&gt;Our delivery teams are very busy, and that’s great! But that shouldn’t stop us, as a platform team, from moving forward. This is where the real benefit of Infrastructure as Code and AWS shows: we can move the whole fleet without asking every team to stop what they’re doing.&lt;/li&gt;&lt;li&gt;There is &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://aws.amazon.com/blogs/database/announcing-valkey-9-1-for-amazon-elasticache/#:~:text=Improve%20price%2Dperformance%20at%20scale&quot;&gt;even more power&lt;/a&gt; ahead in Valkey 9.1!&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;em&gt;I work as a Pathfinder at the &lt;/em&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://wehkampretailgroup.nl/&quot;&gt;&lt;em&gt;Wehkamp Retail Group&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, one of the biggest e-commerce companies of the Netherlands. This article is &lt;/em&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://medium.com/wehkamp-techblog&quot;&gt;&lt;em&gt;part of our Tech Blog&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, check it out &amp;amp; subscribe. Looking for a great job? &lt;/em&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://wehkampretailgroup.nl/vacatures/&quot;&gt;&lt;em&gt;Check our job offers&lt;/em&gt;&lt;/a&gt;&lt;em&gt; or &lt;/em&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.linkedin.com/in/keescbakker/&quot;&gt;&lt;em&gt;drop me a line on LinkedIn&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;&lt;em&gt;Originally published at &lt;/em&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://keestalkstech.com/how-we-switched-150-stores-from-redis-to-valkey-and-nobody-cared/&quot;&gt;&lt;em&gt;keestalkstech.com&lt;/em&gt;&lt;/a&gt;&lt;em&gt; on June 22, 2026.&lt;/em&gt;&lt;/p&gt;&lt;hr&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://medium.com/wehkamp-techblog/how-we-switched-150-stores-from-redis-to-valkey-and-nobody-cared-308b0a8a9fc7&quot;&gt;How we switched 150 stores from Redis to Valkey, and nobody cared!&lt;/a&gt; was originally published in &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://medium.com/wehkamp-techblog&quot;&gt;wehkamp-techblog&lt;/a&gt; on Medium, where people are continuing the conversation by highlighting and responding to this story.&lt;/p&gt;</summary><author><name>Kees C. Bakker</name></author><source gr:stream-id="feed/https://medium.com/feed/wehkamp-techblog"><id>tag:google.com,2005:reader/feed/https://medium.com/feed/wehkamp-techblog</id><title type="html">wehkamp-techblog - Medium</title><link rel="alternate" href="https://medium.com/wehkamp-techblog?source=rss----a3c49d1b884---4" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1783339200000"><id gr:original-id="https://thenewstack.io/?p=22828818">tag:google.com,2005:reader/item/00000b0e000000b4</id><category term="Software Development"></category><category term="Software Testing"></category><category term="Tech Culture"></category><title type="html">The code review bug hunt is dead. Here’s what developers get wrong.</title><published>2026-07-06T12:00:00Z</published><updated>2026-07-06T12:00:00Z</updated><link rel="alternate" href="https://thenewstack.io/code-review-catches-maintainability-bugs/" type="text/html"></link><summary type="html">Engineers and experts say code review rarely catches bugs — its real job is flagging code that&amp;apos;s painful to maintain later.</summary><author><name>Adrian Bridgwater</name></author><source gr:stream-id="feed/https://thenewstack.io/software-testing/feed/"><id>tag:google.com,2005:reader/feed/https://thenewstack.io/software-testing/feed/</id><title type="html">Software Testing Archives - The New Stack</title><link rel="alternate" href="https://thenewstack.io/software-testing/" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1783337881000"><id gr:original-id="https://www.lifeofqa.com/p/testing-beyond-checks">tag:google.com,2005:reader/item/00000fe80000001d</id><title type="html">Testing Beyond Checks</title><published>2026-07-06T11:38:01Z</published><updated>2026-07-06T11:38:01Z</updated><link rel="alternate" href="https://www.lifeofqa.com/p/testing-beyond-checks" type="text/html"></link><summary type="html">&lt;h2&gt;&lt;strong&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://confq.com/courses/2026-virtual&quot;&gt;My ConfQ 2026 Talk&lt;/a&gt;&lt;/strong&gt;&lt;/h2&gt;&lt;p&gt;Last week, I had the privilege of speaking at &lt;strong&gt;ConfQ 2026&lt;/strong&gt; on a topic that has shaped much of my thinking over the past few years:&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;mark data-color=&quot;#ffd966&quot; style=&quot;background-color: rgb(255, 217, 102); color: rgb(0, 0, 0)&quot;&gt;Testing Beyond Checks: Why Passing Checks Is Not the Same as Understanding Risk.&lt;/mark&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;The session wasn’t an argument against automation.&lt;/p&gt;&lt;p&gt;It wasn’t an argument against CI/CD pipelines.&lt;/p&gt;&lt;p&gt;And it certainly wasn’t an argument against checking.&lt;/p&gt;&lt;p&gt;Checking is essential.&lt;/p&gt;&lt;p&gt;Automation is essential.&lt;/p&gt;&lt;p&gt;Fast feedback is essential.&lt;/p&gt;&lt;p&gt;The question I wanted to explore was different:&lt;/p&gt;&lt;p&gt;&lt;strong&gt;What happens when checking quietly becomes our definition of testing?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;That question has influenced many of the articles I’ve written here on &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.lifeofqa.com&quot;&gt;LifeOfQA&lt;/a&gt;. At ConfQ, I had the opportunity to bring those ideas together into one story.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;🎥 Watch the presentation below:&lt;/strong&gt;&lt;/p&gt;&lt;div data-component-name=&quot;VideoPlaceholder&quot; data-attrs=&quot;{&amp;quot;mediaUploadId&amp;quot;:&amp;quot;0e353d6c-426a-4711-873b-566a3c4459c3&amp;quot;,&amp;quot;duration&amp;quot;:null}&quot;&gt;&lt;/div&gt;&lt;div&gt;&lt;hr&gt;&lt;/div&gt;&lt;h2&gt;&lt;strong&gt;The central idea&lt;/strong&gt;&lt;/h2&gt;&lt;p&gt;If I had to summarize the entire presentation in one sentence, it would be this:&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;mark data-color=&quot;#ffd966&quot; style=&quot;background-color: rgb(255, 217, 102); color: rgb(0, 0, 0)&quot;&gt;Evidence of activity is not evidence of understanding.&lt;/mark&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Modern engineering teams generate an incredible amount of evidence.&lt;/p&gt;&lt;p&gt;Coverage reports.&lt;/p&gt;&lt;p&gt;Passing automated checks.&lt;/p&gt;&lt;p&gt;Green pipelines.&lt;/p&gt;&lt;p&gt;Defect dashboards.&lt;/p&gt;&lt;p&gt;Release approvals.&lt;/p&gt;&lt;p&gt;These are all useful signals.&lt;/p&gt;&lt;p&gt;But none of them, on their own, tell us whether we truly understand the risks within our system.&lt;/p&gt;&lt;p&gt;Passing checks tells us that certain expectations were verified.&lt;/p&gt;&lt;p&gt;Testing asks a different question:&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Were our expectations sufficient in the first place?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;That distinction may seem small, but it changes how we think about quality.&lt;/p&gt;&lt;div&gt;&lt;hr&gt;&lt;/div&gt;&lt;h2&gt;&lt;strong&gt;What teams really want&lt;/strong&gt;&lt;/h2&gt;&lt;p&gt;No engineering team wakes up hoping to execute more test cases.&lt;/p&gt;&lt;p&gt;Nobody celebrates increasing code coverage by another one percent.&lt;/p&gt;&lt;p&gt;Those things are tools, not goals.&lt;/p&gt;&lt;p&gt;What teams really want is confidence.&lt;/p&gt;&lt;p&gt;Confidence to release.&lt;/p&gt;&lt;p&gt;Confidence to make changes.&lt;/p&gt;&lt;p&gt;Confidence to move faster.&lt;/p&gt;&lt;p&gt;Confidence to make better decisions.&lt;/p&gt;&lt;p&gt;The problem is that confidence can come from two very different places.&lt;/p&gt;&lt;p&gt;One is built on genuine understanding.&lt;/p&gt;&lt;p&gt;The other is built on signals that simply make us feel safe.&lt;/p&gt;&lt;p&gt;Those are not the same.&lt;/p&gt;&lt;div&gt;&lt;hr&gt;&lt;/div&gt;&lt;h2&gt;&lt;strong&gt;When confidence becomes dangerous&lt;/strong&gt;&lt;/h2&gt;&lt;p&gt;During the talk, I discussed two well-known incidents: &lt;strong&gt;Knight Capital&lt;/strong&gt; and &lt;strong&gt;CrowdStrike&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;Different companies.&lt;/p&gt;&lt;p&gt;Different technologies.&lt;/p&gt;&lt;p&gt;Different industries.&lt;/p&gt;&lt;p&gt;Different years.&lt;/p&gt;&lt;p&gt;Yet they revealed a remarkably similar pattern.&lt;/p&gt;&lt;p&gt;The checks worked.&lt;/p&gt;&lt;p&gt;The assumptions failed.&lt;/p&gt;&lt;p&gt;That gap between what we verified and what we truly understood is where many of our biggest software risks hide.&lt;/p&gt;&lt;p&gt;These examples aren’t meant to criticize those organizations.&lt;/p&gt;&lt;p&gt;They’re reminders that even highly capable teams can miss important risks when confidence becomes disconnected from understanding.&lt;/p&gt;&lt;div&gt;&lt;hr&gt;&lt;/div&gt;&lt;h2&gt;&lt;strong&gt;Why smart teams still fall into this trap&lt;/strong&gt;&lt;/h2&gt;&lt;p&gt;I don’t believe these failures happen because engineers stop caring.&lt;/p&gt;&lt;p&gt;More often, they’re influenced by normal human psychology.&lt;/p&gt;&lt;p&gt;In the talk, I discussed three ideas that explain why intelligent teams can gradually become overconfident:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Automation Bias&lt;/strong&gt; – trusting automated results more than our own judgment.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Goodhart’s Law&lt;/strong&gt; – when a measure becomes a target, it stops being a good measure.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;McNamara Fallacy&lt;/strong&gt; – focusing only on what is easy to measure while ignoring what matters most.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Automation is valuable.&lt;/p&gt;&lt;p&gt;Metrics are valuable.&lt;/p&gt;&lt;p&gt;Dashboards are valuable.&lt;/p&gt;&lt;p&gt;But none of them should replace critical thinking.&lt;/p&gt;&lt;div&gt;&lt;hr&gt;&lt;/div&gt;&lt;h2&gt;&lt;strong&gt;So what does testing actually do?&lt;/strong&gt;&lt;/h2&gt;&lt;p&gt;For me, testing isn’t primarily about execution.&lt;/p&gt;&lt;p&gt;Testing is investigation.&lt;/p&gt;&lt;p&gt;Testing is learning.&lt;/p&gt;&lt;p&gt;Testing is reducing uncertainty.&lt;/p&gt;&lt;p&gt;Checking confirms what we already expect.&lt;/p&gt;&lt;p&gt;Testing explores whether those expectations are complete.&lt;/p&gt;&lt;p&gt;Whenever I begin exploring a new product or feature, I keep returning to three simple questions:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;What assumptions are we making?&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;What could seriously hurt our users?&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;What behavior would genuinely surprise us?&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;These aren’t test cases.&lt;/p&gt;&lt;p&gt;They’re thinking tools.&lt;/p&gt;&lt;p&gt;Good testing often begins with a better question, not a bigger checklist.&lt;/p&gt;&lt;div&gt;&lt;hr&gt;&lt;/div&gt;&lt;h2&gt;&lt;strong&gt;Checking and testing need each other&lt;/strong&gt;&lt;/h2&gt;&lt;p&gt;One misunderstanding I wanted to avoid during the session was the idea that this is somehow an argument against checking.&lt;/p&gt;&lt;p&gt;It isn’t.&lt;/p&gt;&lt;p&gt;Modern software development depends on checking.&lt;/p&gt;&lt;p&gt;Without automated checks, continuous delivery at today’s scale wouldn’t be possible.&lt;/p&gt;&lt;p&gt;But checking and testing perform different jobs.&lt;/p&gt;&lt;p&gt;Checking provides repeatable evidence.&lt;/p&gt;&lt;p&gt;Testing creates understanding.&lt;/p&gt;&lt;p&gt;Quality needs both.&lt;/p&gt;&lt;div&gt;&lt;hr&gt;&lt;/div&gt;&lt;h2&gt;&lt;strong&gt;Testing is a social activity&lt;/strong&gt;&lt;/h2&gt;&lt;p&gt;One of the ideas closest to my heart is that testing is not just a technical activity.&lt;/p&gt;&lt;p&gt;It’s a social one.&lt;/p&gt;&lt;p&gt;Quality doesn’t come from a QA team alone.&lt;/p&gt;&lt;p&gt;It emerges from the decisions developers, testers, product managers, architects, designers, and leaders make together.&lt;/p&gt;&lt;p&gt;Testing contributes information.&lt;/p&gt;&lt;p&gt;It creates understanding.&lt;/p&gt;&lt;p&gt;It helps teams make better decisions.&lt;/p&gt;&lt;p&gt;That’s why I believe risk doesn’t live inside test cases.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Risk lives in conversations.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;One question I encourage teams to replace in release meetings is this:&lt;/p&gt;&lt;p&gt;&lt;strong&gt;“Did all the tests pass?”&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;It’s a useful question.&lt;/p&gt;&lt;p&gt;But it’s incomplete.&lt;/p&gt;&lt;p&gt;Instead, ask:&lt;/p&gt;&lt;p&gt;&lt;strong&gt;“What risks remain?”&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;That single question changes the conversation from reporting activity to discussing uncertainty.&lt;/p&gt;&lt;div&gt;&lt;hr&gt;&lt;/div&gt;&lt;h2&gt;&lt;strong&gt;Final thoughts&lt;/strong&gt;&lt;/h2&gt;&lt;p&gt;If there’s one idea I’d like readers to remember, it’s this:&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;mark data-color=&quot;#ffd966&quot; style=&quot;background-color: rgb(255, 217, 102); color: rgb(0, 0, 0)&quot;&gt;Confidence is not earned by passing checks. Confidence is earned by understanding risk.&lt;/mark&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;The software industry doesn’t need fewer checks.&lt;/p&gt;&lt;p&gt;We need thoughtful checking.&lt;/p&gt;&lt;p&gt;Thoughtful automation.&lt;/p&gt;&lt;p&gt;Thoughtful engineering.&lt;/p&gt;&lt;p&gt;But above all, we need curious people who continue asking questions that dashboards cannot answer.&lt;/p&gt;&lt;p&gt;Because checks provide evidence.&lt;/p&gt;&lt;p&gt;Testing creates understanding.&lt;/p&gt;&lt;p&gt;And quality needs both.&lt;/p&gt;&lt;div&gt;&lt;hr&gt;&lt;/div&gt;&lt;h2&gt;&lt;strong&gt;Further Reading&lt;/strong&gt;&lt;/h2&gt;&lt;p&gt;&lt;em&gt;If you found this useful, you might also enjoy these articles:&lt;/em&gt;&lt;/p&gt;&lt;div data-attrs=&quot;{&amp;quot;nodeId&amp;quot;:&amp;quot;99a1bff4-ccd2-4831-8392-9801d56a8dbc&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;Every few months, the same headlines return:&amp;quot;,&amp;quot;cta&amp;quot;:null,&amp;quot;showBylines&amp;quot;:true,&amp;quot;showDescription&amp;quot;:true,&amp;quot;showImage&amp;quot;:true,&amp;quot;size&amp;quot;:&amp;quot;sm&amp;quot;,&amp;quot;isEditorNode&amp;quot;:true,&amp;quot;title&amp;quot;:&amp;quot;AI vs Human Is the Wrong Debate&amp;quot;,&amp;quot;publishedBylines&amp;quot;:[{&amp;quot;id&amp;quot;:200170262,&amp;quot;name&amp;quot;:&amp;quot;Deepak Karn&amp;quot;,&amp;quot;bio&amp;quot;:&amp;quot;👋 I am Deepak, a Software Test Engineer. I enjoy exploring innovative testing approaches, sharing insights, and helping others navigate the world of software testing. Let’s learn and grow together!&amp;quot;,&amp;quot;photo_url&amp;quot;:&amp;quot;https://substack-post-media.s3.amazonaws.com/public/images/6dd89aef-73d7-46e4-808b-e24883e8873d_640x640.jpeg&amp;quot;,&amp;quot;is_guest&amp;quot;:false,&amp;quot;bestseller_tier&amp;quot;:null}],&amp;quot;post_date&amp;quot;:&amp;quot;2026-06-01T06:44:54.815Z&amp;quot;,&amp;quot;cover_image&amp;quot;:&amp;quot;https://substack-post-media.s3.amazonaws.com/public/images/af61a60d-2afb-4644-ad45-93254cf65afc_1498x994.png&amp;quot;,&amp;quot;cover_image_alt&amp;quot;:null,&amp;quot;canonical_url&amp;quot;:&amp;quot;https://www.lifeofqa.com/p/ai-vs-human-is-the-wrong-debate&amp;quot;,&amp;quot;section_name&amp;quot;:null,&amp;quot;video_upload_id&amp;quot;:null,&amp;quot;id&amp;quot;:200077926,&amp;quot;type&amp;quot;:&amp;quot;newsletter&amp;quot;,&amp;quot;reaction_count&amp;quot;:4,&amp;quot;comment_count&amp;quot;:2,&amp;quot;publication_id&amp;quot;:2282918,&amp;quot;publication_name&amp;quot;:&amp;quot;LifeOfQA&amp;quot;,&amp;quot;publication_logo_url&amp;quot;:&amp;quot;https://substackcdn.com/image/fetch/$s_!7ABd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ca2b04c-1640-4028-b36a-37342a054521_1024x1024.png&amp;quot;,&amp;quot;belowTheFold&amp;quot;:true,&amp;quot;youtube_url&amp;quot;:null,&amp;quot;show_links&amp;quot;:null,&amp;quot;feed_url&amp;quot;:null}&quot;&gt;&lt;/div&gt;&lt;div data-attrs=&quot;{&amp;quot;nodeId&amp;quot;:&amp;quot;01db6129-7819-4359-a8bc-bfffad0498f2&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;Most automation suites don’t protect products.&amp;quot;,&amp;quot;cta&amp;quot;:null,&amp;quot;showBylines&amp;quot;:true,&amp;quot;showDescription&amp;quot;:true,&amp;quot;showImage&amp;quot;:true,&amp;quot;size&amp;quot;:&amp;quot;sm&amp;quot;,&amp;quot;isEditorNode&amp;quot;:true,&amp;quot;title&amp;quot;:&amp;quot;When Automation Creates Confidence Instead of Safety&amp;quot;,&amp;quot;publishedBylines&amp;quot;:[{&amp;quot;id&amp;quot;:200170262,&amp;quot;name&amp;quot;:&amp;quot;Deepak Karn&amp;quot;,&amp;quot;bio&amp;quot;:&amp;quot;👋 I am Deepak, a Software Test Engineer. I enjoy exploring innovative testing approaches, sharing insights, and helping others navigate the world of software testing. Let’s learn and grow together!&amp;quot;,&amp;quot;photo_url&amp;quot;:&amp;quot;https://substack-post-media.s3.amazonaws.com/public/images/6dd89aef-73d7-46e4-808b-e24883e8873d_640x640.jpeg&amp;quot;,&amp;quot;is_guest&amp;quot;:false,&amp;quot;bestseller_tier&amp;quot;:null}],&amp;quot;post_date&amp;quot;:&amp;quot;2026-01-30T05:42:47.039Z&amp;quot;,&amp;quot;cover_image&amp;quot;:&amp;quot;https://substack-post-media.s3.amazonaws.com/public/images/135f7ba0-fc31-43cb-b846-62aaa19418ea_1536x1024.png&amp;quot;,&amp;quot;cover_image_alt&amp;quot;:null,&amp;quot;canonical_url&amp;quot;:&amp;quot;https://www.lifeofqa.com/p/when-automation-creates-confidence&amp;quot;,&amp;quot;section_name&amp;quot;:null,&amp;quot;video_upload_id&amp;quot;:null,&amp;quot;id&amp;quot;:186181482,&amp;quot;type&amp;quot;:&amp;quot;newsletter&amp;quot;,&amp;quot;reaction_count&amp;quot;:3,&amp;quot;comment_count&amp;quot;:0,&amp;quot;publication_id&amp;quot;:2282918,&amp;quot;publication_name&amp;quot;:&amp;quot;LifeOfQA&amp;quot;,&amp;quot;publication_logo_url&amp;quot;:&amp;quot;https://substackcdn.com/image/fetch/$s_!7ABd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ca2b04c-1640-4028-b36a-37342a054521_1024x1024.png&amp;quot;,&amp;quot;belowTheFold&amp;quot;:true,&amp;quot;youtube_url&amp;quot;:null,&amp;quot;show_links&amp;quot;:null,&amp;quot;feed_url&amp;quot;:null}&quot;&gt;&lt;/div&gt;&lt;div data-attrs=&quot;{&amp;quot;nodeId&amp;quot;:&amp;quot;bc3d0d84-c4c2-4ad3-973d-ae6c676dd445&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;Can Developers Test?&amp;quot;,&amp;quot;cta&amp;quot;:null,&amp;quot;showBylines&amp;quot;:true,&amp;quot;showDescription&amp;quot;:true,&amp;quot;showImage&amp;quot;:true,&amp;quot;size&amp;quot;:&amp;quot;sm&amp;quot;,&amp;quot;isEditorNode&amp;quot;:true,&amp;quot;title&amp;quot;:&amp;quot;Can Developers Test?&amp;quot;,&amp;quot;publishedBylines&amp;quot;:[{&amp;quot;id&amp;quot;:200170262,&amp;quot;name&amp;quot;:&amp;quot;Deepak Karn&amp;quot;,&amp;quot;bio&amp;quot;:&amp;quot;👋 I am Deepak, a Software Test Engineer. I enjoy exploring innovative testing approaches, sharing insights, and helping others navigate the world of software testing. Let’s learn and grow together!&amp;quot;,&amp;quot;photo_url&amp;quot;:&amp;quot;https://substack-post-media.s3.amazonaws.com/public/images/6dd89aef-73d7-46e4-808b-e24883e8873d_640x640.jpeg&amp;quot;,&amp;quot;is_guest&amp;quot;:false,&amp;quot;bestseller_tier&amp;quot;:null}],&amp;quot;post_date&amp;quot;:&amp;quot;2025-10-14T07:13:34.387Z&amp;quot;,&amp;quot;cover_image&amp;quot;:&amp;quot;https://substack-post-media.s3.amazonaws.com/public/images/7c258a04-705b-436e-a2e6-f8701aad620f_1536x1024.png&amp;quot;,&amp;quot;cover_image_alt&amp;quot;:null,&amp;quot;canonical_url&amp;quot;:&amp;quot;https://www.lifeofqa.com/p/can-developers-test&amp;quot;,&amp;quot;section_name&amp;quot;:null,&amp;quot;video_upload_id&amp;quot;:null,&amp;quot;id&amp;quot;:176116999,&amp;quot;type&amp;quot;:&amp;quot;newsletter&amp;quot;,&amp;quot;reaction_count&amp;quot;:3,&amp;quot;comment_count&amp;quot;:0,&amp;quot;publication_id&amp;quot;:2282918,&amp;quot;publication_name&amp;quot;:&amp;quot;LifeOfQA&amp;quot;,&amp;quot;publication_logo_url&amp;quot;:&amp;quot;https://substackcdn.com/image/fetch/$s_!7ABd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ca2b04c-1640-4028-b36a-37342a054521_1024x1024.png&amp;quot;,&amp;quot;belowTheFold&amp;quot;:true,&amp;quot;youtube_url&amp;quot;:null,&amp;quot;show_links&amp;quot;:null,&amp;quot;feed_url&amp;quot;:null}&quot;&gt;&lt;/div&gt;&lt;div data-attrs=&quot;{&amp;quot;nodeId&amp;quot;:&amp;quot;f31cbf97-b636-445d-a46a-e32c020a05fc&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;Testing isn&amp;apos;t about following perfect steps. It&amp;apos;s about wrestling with uncertainty, trusting your gut, and finding problems others miss. Let&amp;apos;s talk about how to think, not just what to check.&amp;quot;,&amp;quot;cta&amp;quot;:null,&amp;quot;showBylines&amp;quot;:true,&amp;quot;showDescription&amp;quot;:true,&amp;quot;showImage&amp;quot;:true,&amp;quot;size&amp;quot;:&amp;quot;sm&amp;quot;,&amp;quot;isEditorNode&amp;quot;:true,&amp;quot;title&amp;quot;:&amp;quot;🧠 Critical Thinking in Testing: When Things Get Messy&amp;quot;,&amp;quot;publishedBylines&amp;quot;:[{&amp;quot;id&amp;quot;:200170262,&amp;quot;name&amp;quot;:&amp;quot;Deepak Karn&amp;quot;,&amp;quot;bio&amp;quot;:&amp;quot;👋 I am Deepak, a Software Test Engineer. I enjoy exploring innovative testing approaches, sharing insights, and helping others navigate the world of software testing. Let’s learn and grow together!&amp;quot;,&amp;quot;photo_url&amp;quot;:&amp;quot;https://substack-post-media.s3.amazonaws.com/public/images/6dd89aef-73d7-46e4-808b-e24883e8873d_640x640.jpeg&amp;quot;,&amp;quot;is_guest&amp;quot;:false,&amp;quot;bestseller_tier&amp;quot;:null}],&amp;quot;post_date&amp;quot;:&amp;quot;2025-08-18T11:49:01.464Z&amp;quot;,&amp;quot;cover_image&amp;quot;:&amp;quot;https://substack-post-media.s3.amazonaws.com/public/images/18c0cbec-7c1e-4d5d-be23-6950f0497455_1024x1536.png&amp;quot;,&amp;quot;cover_image_alt&amp;quot;:null,&amp;quot;canonical_url&amp;quot;:&amp;quot;https://www.lifeofqa.com/p/critical-thinking-in-testing-when&amp;quot;,&amp;quot;section_name&amp;quot;:null,&amp;quot;video_upload_id&amp;quot;:null,&amp;quot;id&amp;quot;:171254729,&amp;quot;type&amp;quot;:&amp;quot;newsletter&amp;quot;,&amp;quot;reaction_count&amp;quot;:7,&amp;quot;comment_count&amp;quot;:4,&amp;quot;publication_id&amp;quot;:2282918,&amp;quot;publication_name&amp;quot;:&amp;quot;LifeOfQA&amp;quot;,&amp;quot;publication_logo_url&amp;quot;:&amp;quot;https://substackcdn.com/image/fetch/$s_!7ABd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ca2b04c-1640-4028-b36a-37342a054521_1024x1024.png&amp;quot;,&amp;quot;belowTheFold&amp;quot;:true,&amp;quot;youtube_url&amp;quot;:null,&amp;quot;show_links&amp;quot;:null,&amp;quot;feed_url&amp;quot;:null}&quot;&gt;&lt;/div&gt;&lt;div&gt;&lt;hr&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;If you found this helpful, stay connected with &lt;/strong&gt;&lt;em&gt;&lt;strong&gt;Life of QA&lt;/strong&gt;&lt;/em&gt;&lt;strong&gt; for more real-world testing experiences, tips, and lessons from the journey!&lt;/strong&gt;&lt;/p&gt;&lt;p data-attrs=&quot;{&amp;quot;url&amp;quot;:&amp;quot;https://www.lifeofqa.com/subscribe?&amp;quot;,&amp;quot;text&amp;quot;:&amp;quot;Subscribe now&amp;quot;,&amp;quot;action&amp;quot;:null,&amp;quot;class&amp;quot;:null}&quot; data-component-name=&quot;ButtonCreateButton&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.lifeofqa.com/subscribe?&quot;&gt;&lt;span&gt;Subscribe now&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p data-attrs=&quot;{&amp;quot;url&amp;quot;:&amp;quot;https://www.lifeofqa.com/p/testing-beyond-checks/comments&amp;quot;,&amp;quot;text&amp;quot;:&amp;quot;Leave a comment&amp;quot;,&amp;quot;action&amp;quot;:null,&amp;quot;class&amp;quot;:null}&quot; data-component-name=&quot;ButtonCreateButton&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://www.lifeofqa.com/p/testing-beyond-checks/comments&quot;&gt;&lt;span&gt;Leave a comment&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p data-attrs=&quot;{&amp;quot;url&amp;quot;:&amp;quot;https://buymeacoffee.com/lifeofqa&amp;quot;,&amp;quot;text&amp;quot;:&amp;quot;☕️ Buy me a coffee&amp;quot;,&amp;quot;action&amp;quot;:null,&amp;quot;class&amp;quot;:null}&quot; data-component-name=&quot;ButtonCreateButton&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://buymeacoffee.com/lifeofqa&quot;&gt;&lt;span&gt;☕️ Buy me a coffee&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p style=&quot;clear: both&quot;&gt;&lt;/p&gt;&lt;p data-bqr-info=&quot;attachment&quot;&gt;&lt;img class=&quot;bqrUnknownImgSize&quot; src=&quot;https://substack-post-media.s3.amazonaws.com/public/images/2e7869f9-5517-464f-969b-404efce969fc_3360x1744.png&quot;&gt;&lt;/p&gt;</summary><author><name>Deepak Karn</name></author><source gr:stream-id="feed/https://www.lifeofqa.com/feed"><id>tag:google.com,2005:reader/feed/https://www.lifeofqa.com/feed</id><title type="html">LifeOfQA</title><link rel="alternate" href="https://www.lifeofqa.com" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1783313583000"><id gr:original-id="https://qualityremarks.com/?p=6998">tag:google.com,2005:reader/item/00000463000004c6</id><category term="Software Testing"></category><title type="html">The AI House – AI Priorities in the Enterprise</title><published>2026-07-06T04:53:03Z</published><updated>2026-07-06T04:53:03Z</updated><link rel="alternate" href="https://qualityremarks.com/the-ai-house-ai-priorities-in-the-enterprise/" type="text/html"></link><summary type="html">&lt;p&gt;Here’s the full video of the round table I moderated for The AI House at KPMG – Enjoy!&lt;/p&gt;



&lt;figure&gt;&lt;div&gt;
&lt;iframe width=&quot;640&quot; height=&quot;360&quot; style=&quot;border: 0&quot; src=&quot;https://www.youtube.com/embed/AdEwb6Wju-U?version=3&amp;amp;rel=1&amp;amp;showsearch=0&amp;amp;showinfo=1&amp;amp;iv_load_policy=1&amp;amp;fs=1&amp;amp;hl=en-US&amp;amp;wmode=transparent&amp;amp;autoplay=0&amp;amp;rel=0&amp;amp;playsinline=1&amp;amp;modestbranding=1&amp;amp;origin=https:%2f%2fbazqux.com&quot; allow=&quot;autoplay; fullscreen; encrypted-media; clipboard-write; picture-in-picture; web-share&quot; sandbox=&quot;allow-same-origin allow-scripts allow-forms allow-popups allow-presentation&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;&lt;/figure&gt;The post &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://qualityremarks.com/the-ai-house-ai-priorities-in-the-enterprise/&quot;&gt;The AI House – AI Priorities in the Enterprise&lt;/a&gt; first appeared on &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://qualityremarks.com&quot;&gt;Quality Remarks&lt;/a&gt;.</summary><author><name>keithklain</name></author><source gr:stream-id="feed/http://qualityremarks.com/feed/"><id>tag:google.com,2005:reader/feed/http://qualityremarks.com/feed/</id><title type="html">Quality Remarks</title><link rel="alternate" href="https://qualityremarks.com" type="text/html"></link></source></entry><entry gr:crawl-timestamp-msec="1783312402000"><id gr:original-id="https://scrolltest.com/browser-agent-testing-day-29/">tag:google.com,2005:reader/item/0000044400000284</id><category term="AI Testing"></category><category term="Testing"></category><category term="CI/CD"></category><category term="SDET"></category><category term="test automation"></category><title type="html">Browser Agent Testing: Day 29 Trust Report</title><published>2026-07-06T04:33:22Z</published><updated>2026-07-06T04:33:22Z</updated><link rel="alternate" href="https://scrolltest.com/browser-agent-testing-day-29/" type="text/html"></link><summary type="html">&lt;p&gt;Day 29 of 100 Days of AI in QA shows how to turn browser agent testing from a demo into a trust report with evidence, risk scoring, and CI gates.&lt;/p&gt;
&lt;p&gt;The post &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; rel=&quot;nofollow&quot; href=&quot;https://scrolltest.com/browser-agent-testing-day-29/&quot;&gt;Browser Agent Testing: Day 29 Trust Report&lt;/a&gt; appeared first on &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; rel=&quot;nofollow&quot; href=&quot;https://scrolltest.com&quot;&gt;Software Testing &amp;amp; Automation&lt;/a&gt;.&lt;/p&gt;</summary><author><name>Promode</name></author><source gr:stream-id="feed/https://scrolltest.com/feed/"><id>tag:google.com,2005:reader/feed/https://scrolltest.com/feed/</id><title type="html">Software Testing &amp; Automation</title><link rel="alternate" href="https://scrolltest.com" type="text/html"></link></source></entry></feed>