<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Engineering on jpcercal.com</title><link>https://jpcercal.com/en/categories/engineering/</link><description>Recent content in Engineering on jpcercal.com</description><generator>Hugo</generator><language>en</language><lastBuildDate>Thu, 22 Oct 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://jpcercal.com/en/categories/engineering/index.xml" rel="self" type="application/rss+xml"/><item><title>A WAF Is Not a Patch</title><link>https://jpcercal.com/en/a-waf-is-not-a-patch/</link><pubDate>Thu, 22 Oct 2026 00:00:00 +0000</pubDate><guid>https://jpcercal.com/en/a-waf-is-not-a-patch/</guid><description>&lt;p&gt;A critical CVE lands. Someone asks in the team chat whether we are exposed, and the first reply is &amp;ldquo;we have a WAF, we&amp;rsquo;re covered.&amp;rdquo;&lt;/p&gt;&#10;&lt;p&gt;I understand the reflex. A WAF is one of the fastest ways to react, and I would not want to run a public application without one. But the sentence mixes up two different things. A WAF changes the odds that an attacker reaches a bug. A patch removes the bug. When the first gets treated as the second, a temporary bridge quietly becomes permanent infrastructure.&lt;/p&gt;</description></item><item><title>PHP2Shell: Two Critical PHP Vulnerabilities and What to Do Now</title><link>https://jpcercal.com/en/php2shell-two-critical-php-vulnerabilities/</link><pubDate>Wed, 21 Oct 2026 00:00:00 +0000</pubDate><guid>https://jpcercal.com/en/php2shell-two-critical-php-vulnerabilities/</guid><description>&lt;p&gt;Two critical flaws in the PHP runtime itself were disclosed on October 21, 2026: CVE-2026-109618 and CVE-2026-109619, nicknamed “PHP2Shell.” Both are CVSS 9.2 (v4.0) and can lead to unauthenticated remote code execution. Disclosure was moved up a day after the IDs leaked (&lt;a href="https://thephp.foundation/blog/2026/10/21/todays-php-security-release-and-how-were-strengthening-php-security/"&gt;PHP Foundation&lt;/a&gt;). The bug is in PHP core, so your framework does not matter.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;The short version:&lt;/strong&gt; update PHP to 8.5.12, 8.4.27, 8.3.36 or 8.2.35, restart every worker, and verify the running version. A WAF buys time; it is not a patch.&lt;/p&gt;</description></item><item><title>Changing the Decision Model Changes the Policy</title><link>https://jpcercal.com/en/changing-the-decision-model-changes-the-policy/</link><pubDate>Sun, 11 Oct 2026 00:00:00 +0000</pubDate><guid>https://jpcercal.com/en/changing-the-decision-model-changes-the-policy/</guid><description>&lt;p&gt;I&amp;rsquo;ve been reading Vercel&amp;rsquo;s comparison of Jev, Laya, and Liquid d1, and the useful part for me is not which model wins.&lt;/p&gt;&#10;&lt;p&gt;The article does not establish a winner.&lt;/p&gt;&#10;&lt;p&gt;It shows that all three can answer the same typed questions through AI Gateway. That makes comparing them easier. It does not tell us whether the application should act on their answers in the same way.&lt;/p&gt;&#10;&lt;p&gt;That is the distinction I would keep before changing a model in an existing system.&lt;/p&gt;</description></item><item><title>GPT-6 Astra Is an Operator, Not a Chatbot</title><link>https://jpcercal.com/en/gpt-6-astra-is-an-operator-not-a-chatbot/</link><pubDate>Thu, 24 Sep 2026 00:00:00 +0000</pubDate><guid>https://jpcercal.com/en/gpt-6-astra-is-an-operator-not-a-chatbot/</guid><description>&lt;p&gt;I&amp;rsquo;ve been thinking about GPT-6 Astra less as a new chatbot and more as a standing offer to operate the computer.&lt;/p&gt;&#10;&lt;p&gt;OpenAI calls it &amp;ldquo;the world&amp;rsquo;s most intelligent and aligned model.&amp;rdquo; Perhaps. The claim I can check is narrower. On the &lt;a href="https://openai.com/index/gpt-6-astra/"&gt;launch note&lt;/a&gt; and the later &lt;a href="https://openai.com/index/gpt-6-astra-next-generation-work/"&gt;work note&lt;/a&gt;, Astra is described as something that uses the applications people already have open, including applications with no API.&lt;/p&gt;&#10;&lt;p&gt;That is the distinction I would use.&lt;/p&gt;</description></item><item><title>The Cost of the Loop Matters More Than the Score</title><link>https://jpcercal.com/en/the-cost-of-the-loop-matters-more-than-the-score/</link><pubDate>Wed, 23 Sep 2026 18:00:00 +0000</pubDate><guid>https://jpcercal.com/en/the-cost-of-the-loop-matters-more-than-the-score/</guid><description>&lt;p&gt;I&amp;rsquo;ve been reading Anthropic&amp;rsquo;s notes on Claude Opus 5.5, and the part I keep coming back to is not the leaderboard.&lt;/p&gt;&#10;&lt;p&gt;They say it performs at the level of Claude Fable 5.1 on most work, and that in their own use the gap is narrower than the benchmark scores suggest. They also say that at this level of capability, benchmark margins have become a less reliable guide to real-world differences.&lt;/p&gt;</description></item><item><title>When AI Decisions Become Software Inputs</title><link>https://jpcercal.com/en/when-ai-decisions-become-software-inputs/</link><pubDate>Wed, 23 Sep 2026 00:00:00 +0000</pubDate><guid>https://jpcercal.com/en/when-ai-decisions-become-software-inputs/</guid><description>&lt;p&gt;I&amp;rsquo;ve been thinking about what software actually needs when it asks an AI system where to send a request.&lt;/p&gt;&#10;&lt;p&gt;Usually it is not another paragraph. It is an answer it can inspect: a known category, an indication of uncertainty, and a rule for what happens next.&lt;/p&gt;&#10;&lt;p&gt;Consider a support message: “I was charged twice, and the receipt page will not load.” A free-form explanation might help a person, but the application still has to decide which queue receives the message. Parsing prose into a queue name adds another place for the workflow to fail.&lt;/p&gt;</description></item><item><title>What an AI Session Can Teach the Next One</title><link>https://jpcercal.com/en/what-an-ai-session-can-teach-the-next-one/</link><pubDate>Mon, 14 Sep 2026 00:00:00 +0000</pubDate><guid>https://jpcercal.com/en/what-an-ai-session-can-teach-the-next-one/</guid><description>&lt;p&gt;An AI assistant can help write code, explain an unfamiliar system, investigate a failure, or draft documentation. An AI agent can go a step further and take several actions on our behalf.&lt;/p&gt;&#10;&lt;p&gt;In both cases, it is easy to focus only on the immediate result. Did the code compile? Did the document look reasonable? Did the task move forward?&lt;/p&gt;&#10;&lt;p&gt;There is another result that is easy to lose: what the session taught us about the way our team works.&lt;/p&gt;</description></item><item><title>Working With AI Agents: Stay on the Loop</title><link>https://jpcercal.com/en/working-with-ai-agents-stay-on-the-loop/</link><pubDate>Sun, 13 Sep 2026 00:00:00 +0000</pubDate><guid>https://jpcercal.com/en/working-with-ai-agents-stay-on-the-loop/</guid><description>&lt;p&gt;I&amp;rsquo;ve been thinking recently about how our role as software engineers changes when AI agents become part of the development process.&lt;/p&gt;&#10;&lt;p&gt;There seems to be a tempting choice between two extremes.&lt;/p&gt;&#10;&lt;p&gt;Either we let the agent handle everything and trust the result, or we stay involved in every step, reviewing every piece of code it produces.&lt;/p&gt;&#10;&lt;p&gt;I don&amp;rsquo;t think either approach scales particularly well.&lt;/p&gt;&#10;&lt;h2 id="the-output-isnt-the-whole-process"&gt;The output isn&amp;rsquo;t the whole process&lt;/h2&gt;&#10;&lt;p&gt;When building software, we often focus heavily on the artifacts we produce: code, tests, technical designs, configuration, and documentation.&lt;/p&gt;</description></item><item><title>Understand the System Before Changing It</title><link>https://jpcercal.com/en/understand-the-system-before-changing-it/</link><pubDate>Thu, 10 Sep 2026 00:00:00 +0000</pubDate><guid>https://jpcercal.com/en/understand-the-system-before-changing-it/</guid><description>&lt;p&gt;One thing I&amp;rsquo;ve learned over the years is that good architecture often starts with understanding the system you already have.&lt;/p&gt;&#10;&lt;p&gt;Before changing something, I usually invest some time looking at how requests actually flow, where the dependencies are, what the failure points might be, and perhaps most importantly&amp;hellip; why things ended up the way they are.&lt;/p&gt;&#10;&lt;p&gt;Sometimes there&amp;rsquo;s a very good reason. Sometimes the reason is simply that the system evolved over time. Either way, understanding the context usually leads to better decisions than jumping straight to a solution.&lt;/p&gt;</description></item><item><title>How to Create a Bidirectional File Sync using Unison</title><link>https://jpcercal.com/en/how-to-create-a-bidirectional-file-sync-using-unison/</link><pubDate>Mon, 13 Jul 2020 06:35:28 +0000</pubDate><guid>https://jpcercal.com/en/how-to-create-a-bidirectional-file-sync-using-unison/</guid><description>&lt;p&gt;So if you came here I consider you already have a problem to solve, and you are familiar with &lt;code&gt;unison&lt;/code&gt;. If this is the case, skip the introduction please.&lt;/p&gt;&#10;&lt;p&gt;If you don&amp;rsquo;t, then keep reading as it might clarify a few things before we get started with the how to use &lt;code&gt;unison&lt;/code&gt; in order to create a bidirectional (two way) synchronization of two directories.&lt;/p&gt;&#10;&lt;h1 id="introduction"&gt;Introduction&lt;/h1&gt;&#10;&lt;p&gt;To simplify the understanding let&amp;rsquo;s imagine that you have two folders and you want both folders to be synchronized when an event happens such as a new file is created, a file got changed or even a file got deleted. You want both folders to reflect exactly the same state as a replica.&lt;/p&gt;</description></item><item><title>Composer clear cache</title><link>https://jpcercal.com/en/composer-clear-cache/</link><pubDate>Sun, 31 Mar 2019 20:53:12 +0000</pubDate><guid>https://jpcercal.com/en/composer-clear-cache/</guid><description>&lt;p&gt;Well, today I was facing the follow issue:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;End-of-central-directory signature not found. Either this file is not&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; a zipfile, or it constitutes one disk of a multi-part archive. In the&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; latter &lt;span class="k"&gt;case&lt;/span&gt; the central directory and zipfile comment will be found on&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; the last disk&lt;span class="o"&gt;(&lt;/span&gt;s&lt;span class="o"&gt;)&lt;/span&gt; of this archive.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;unzip: cannot find zipfile directory in one of /var/www/apps/api/vendor/symfony/symfony/d9b1f549001f508e27a7334590534b83 or&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; /var/www/apps/api/vendor/symfony/symfony/d9b1f549001f508e27a7334590534b83.zip, and cannot find /var/www/apps/api/vendor/symfony/symfony/d9b1f549001f508e27a7334590534b83.ZIP, period.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; The archive may contain identical file names with different capitalization &lt;span class="o"&gt;(&lt;/span&gt;which fails on &lt;span class="k"&gt;case&lt;/span&gt; insensitive filesystems&lt;span class="o"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Unzip with unzip &lt;span class="nb"&gt;command&lt;/span&gt; failed, falling back to ZipArchive class&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Invalid zip file, retrying...&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;blockquote&gt;&#10;&lt;p&gt;It was part of the output message after executing &lt;code&gt;composer install&lt;/code&gt; command.&lt;/p&gt;</description></item><item><title>Revisiting the layout and the Blog project</title><link>https://jpcercal.com/en/revisiting-the-layout-and-the-blog-project/</link><pubDate>Tue, 12 Mar 2019 21:33:54 +0000</pubDate><guid>https://jpcercal.com/en/revisiting-the-layout-and-the-blog-project/</guid><description>&lt;p&gt;Hello dear visitor, a long time ago I had the desire to revisit the Blog layout, however, conciliate attention to my family and write are not things that could be done at the same time, because, both of them requires dedication.&lt;/p&gt;&#10;&lt;p&gt;Well, technically speaking, the goal was to give back to the open-source community something and so the source code is hosted on GitHub. You can use it to inspire yourself by taking this project as a solid base or even as a starting point.&lt;/p&gt;</description></item><item><title>How to delete all your Git local branches</title><link>https://jpcercal.com/en/how-to-delete-all-your-git-local-branches/</link><pubDate>Tue, 12 Mar 2019 11:31:29 +0000</pubDate><guid>https://jpcercal.com/en/how-to-delete-all-your-git-local-branches/</guid><description>&lt;p&gt;Well, from time to time I feel the need of cleaning my local branches, it’s part of my natural workflow and if you need the same you could benefit as well of this handful pipped command below:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ git branch --list &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;egrep --invert-match &lt;span class="s2"&gt;&amp;#34;(master|gh-pages|\*)&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;xargs git branch -D&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;So, I believe the command listed above is self-explained, but if you didn’t understand what’s going on then, here’s the explanation for each on of them:&lt;/p&gt;</description></item><item><title>iTerm2 + Zplug = Productivity</title><link>https://jpcercal.com/en/iterm2-plus-zplug-means-productivity/</link><pubDate>Mon, 26 Feb 2018 10:15:56 +0000</pubDate><guid>https://jpcercal.com/en/iterm2-plus-zplug-means-productivity/</guid><description>&lt;p&gt;After spending a long time of my life using the normal terminal I met a new tool called iTerm2 because a friend of mine a few years ago. And, this week I&amp;rsquo;ve discovered the power of zplug. So, here&amp;rsquo;s a brief tutorial on how to get something looking similar to this:&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="terminal.png" alt="iTerm2 &amp;#43; zplug" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;h2 id="iterm2"&gt;iTerm2&lt;/h2&gt;&#10;&lt;p&gt;This is a tool like the native app for terminal provided by Apple that has a lot of features that you can just &lt;a href="https://www.iterm2.com/"&gt;check here&lt;/a&gt;. It allows you to customize everything from autocomplete to syntax highlight.&lt;/p&gt;</description></item><item><title>Accessing Amazon RDS Instances from your Desktop</title><link>https://jpcercal.com/en/accessing-amazon-rds-instances-from-your-desktop/</link><pubDate>Fri, 15 Aug 2014 10:48:28 +0000</pubDate><guid>https://jpcercal.com/en/accessing-amazon-rds-instances-from-your-desktop/</guid><description>&lt;p&gt;After a few minutes of research, I found an interesting solution for connecting to Amazon RDS through a Desktop client, well, the magic formula is an SSH connection that forwards packets to the local machine, allowing a remote connection this way.&lt;/p&gt;&#10;&lt;p&gt;First you need to add your Amazon EC2 service connection key. Do this by running the following command:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ ssh-add &amp;lt;your-key-filename&amp;gt;.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;And to forward the packets, run the following command:&lt;/p&gt;</description></item></channel></rss>