<?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>DEV Community: Umer Amin Durrani</title>
    <description>The latest articles on DEV Community by Umer Amin Durrani (@umeramindurrani).</description>
    <link>https://dev.to/umeramindurrani</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4212627%2Fd8514a1f-178f-48c3-870b-d6d4d1077670.jpg</url>
      <title>DEV Community: Umer Amin Durrani</title>
      <link>https://dev.to/umeramindurrani</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/umeramindurrani"/>
    <language>en</language>
    <item>
      <title>Your PostgreSQL Backup Finished. Can You Actually Restore It?</title>
      <dc:creator>Umer Amin Durrani</dc:creator>
      <pubDate>Sat, 07 Nov 2026 08:57:00 +0000</pubDate>
      <link>https://dev.to/umeramindurrani/your-postgresql-backup-finished-can-you-actually-restore-it-53oo</link>
      <guid>https://dev.to/umeramindurrani/your-postgresql-backup-finished-can-you-actually-restore-it-53oo</guid>
      <description>&lt;p&gt;The backup job is green. The file exists. Someone says, “Sorted, bro.”&lt;/p&gt;

&lt;p&gt;Lovely. One tiny question before we all go for chai:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can the application actually use what comes back out of that file?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A completed backup is useful evidence that a backup operation finished. Recovery needs more evidence: that you can access the backup, restore it into a suitable environment, validate the data and bring the service back within acceptable limits.&lt;/p&gt;

&lt;p&gt;A charger in your bag is reassuring. Finding out it fits a different phone is a less enjoyable experience at 2% battery.&lt;/p&gt;

&lt;p&gt;Here is a small PostgreSQL restore exercise you can adapt. It is a lab walkthrough, not a report of a production incident or a measured recovery benchmark.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this exercise proves—and what it doesn't
&lt;/h2&gt;

&lt;p&gt;We will create synthetic data, make a logical backup, restore it into a &lt;strong&gt;new database&lt;/strong&gt;, and compare a few expected results.&lt;/p&gt;

&lt;p&gt;It does not establish disaster recovery for a whole platform. It does not restore your operating system, object storage, application secrets or external services. A logical dump is one component of a recovery strategy; your needs may call for physical backups, WAL archiving or managed-service recovery features instead.&lt;/p&gt;

&lt;p&gt;PostgreSQL documents these distinctions in its &lt;a href="https://www.postgresql.org/docs/18/backup.html" rel="noopener noreferrer"&gt;backup overview&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Start with a disposable environment
&lt;/h2&gt;

&lt;p&gt;Use a non-production PostgreSQL instance and a database role allowed to create databases. The example assumes compatible PostgreSQL client tools are installed and that &lt;code&gt;PGHOST&lt;/code&gt;, &lt;code&gt;PGPORT&lt;/code&gt; and &lt;code&gt;PGUSER&lt;/code&gt; point to that lab instance. Use your normal secure authentication method; keep passwords out of shell history and shared screenshots.&lt;/p&gt;

&lt;p&gt;The commands below do not delete an existing database. Keep them in the same Bash session so their variables remain available.&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="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail
&lt;span class="nb"&gt;umask &lt;/span&gt;077

: &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PGHOST&lt;/span&gt;:?Set&lt;span class="p"&gt; PGHOST to your disposable lab server&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
: &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PGUSER&lt;/span&gt;:?Set&lt;span class="p"&gt; PGUSER to your lab role&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nv"&gt;LAB_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;mktemp&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;LAB_SUFFIX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%s&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="nv"&gt;$$&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;SOURCE_DB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"restore_source_&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;LAB_SUFFIX&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;RESTORE_DB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"restore_target_&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;LAB_SUFFIX&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

createdb &lt;span class="nt"&gt;--template&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;template0 &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SOURCE_DB&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the host before running this. “I thought that terminal was staging” is a sentence with surprisingly expensive punctuation.&lt;/p&gt;

&lt;p&gt;See the &lt;a href="https://www.postgresql.org/docs/18/app-createdb.html" rel="noopener noreferrer"&gt;createdb documentation&lt;/a&gt; for connection and permission details.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Create a small dataset with an actual relationship
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;psql &lt;span class="nt"&gt;--dbname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SOURCE_DB&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--set&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;ON_ERROR_STOP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;SQL&lt;/span&gt;&lt;span class="sh"&gt;'
CREATE TABLE customers (
  id integer PRIMARY KEY,
  name text NOT NULL
);

CREATE TABLE orders (
  id integer PRIMARY KEY,
  customer_id integer NOT NULL REFERENCES customers(id),
  amount_paisa integer NOT NULL CHECK (amount_paisa &amp;gt;= 0)
);

INSERT INTO customers VALUES
  (1, 'Lab customer A'),
  (2, 'Lab customer B');

INSERT INTO orders VALUES
  (101, 1, 1000),
  (102, 1, 2200),
  (103, 2, 1000);
&lt;/span&gt;&lt;span class="no"&gt;SQL
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives us something more useful than checking that a database name exists: rows, a foreign-key relationship and a numeric total.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Create and inspect the archive
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pg_dump &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;custom &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LAB_DIR&lt;/span&gt;&lt;span class="s2"&gt;/application.dump"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SOURCE_DB&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

pg_restore &lt;span class="nt"&gt;--list&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LAB_DIR&lt;/span&gt;&lt;span class="s2"&gt;/application.dump"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LAB_DIR&lt;/span&gt;&lt;span class="s2"&gt;/archive-contents.txt"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first command produces an archive. The second shows its table of contents. &lt;strong&gt;Listing the archive is not a successful restore test.&lt;/strong&gt; It is an intermediate inspection step.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pg_dump&lt;/code&gt; handles one database; global objects such as roles require separate planning. Keep client/server version compatibility in mind. &lt;a href="https://www.postgresql.org/docs/18/app-pgdump.html" rel="noopener noreferrer"&gt;PostgreSQL pg_dump reference&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Restore into a fresh target
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;createdb &lt;span class="nt"&gt;--template&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;template0 &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$RESTORE_DB&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

pg_restore &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--dbname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$RESTORE_DB&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--single-transaction&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--exit-on-error&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--no-owner&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--no-privileges&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LAB_DIR&lt;/span&gt;&lt;span class="s2"&gt;/application.dump"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For this small lab, one transaction helps avoid leaving a partially restored result if a restore command fails. Larger restores may need a different strategy; transaction scope, resource use and parallelism involve trade-offs.&lt;/p&gt;

&lt;p&gt;The owner and privilege options deliberately simplify this lab. &lt;strong&gt;They also mean we have not tested restoration of the production permission model.&lt;/strong&gt; Do not silently carry that assumption into a real recovery plan.&lt;/p&gt;

&lt;p&gt;Only restore trusted archives. A database dump can contain executable database definitions. &lt;a href="https://www.postgresql.org/docs/18/app-pgrestore.html" rel="noopener noreferrer"&gt;PostgreSQL pg_restore reference&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Verify useful properties
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;psql &lt;span class="nt"&gt;--dbname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$RESTORE_DB&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--set&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;ON_ERROR_STOP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;SQL&lt;/span&gt;&lt;span class="sh"&gt;'
SELECT count(*) AS customers FROM customers;
SELECT count(*) AS orders FROM orders;
SELECT sum(amount_paisa) AS total_paisa FROM orders;

SELECT count(*) AS orphan_orders
FROM orders o
LEFT JOIN customers c ON c.id = o.customer_id
WHERE c.id IS NULL;
&lt;/span&gt;&lt;span class="no"&gt;SQL
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For this synthetic dataset, the expected results are &lt;strong&gt;2 customers, 3 orders, 4,200 paisa and 0 orphan orders&lt;/strong&gt;. These values were reproduced during draft verification in an isolated PostgreSQL 18 cluster using synthetic data. They are not results from a production recovery test.&lt;/p&gt;

&lt;p&gt;Counts and totals are useful checks, but they do not prove every value is correct. For a real system, add domain-specific checks: representative records, critical relationships, known transactions and application workflows.&lt;/p&gt;

&lt;p&gt;Then test through the application using its normal restricted role. A restore that works only for an administrator has not yet demonstrated that your service can operate.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Technical PM part: define “recovered” before the incident
&lt;/h2&gt;

&lt;p&gt;Ask the team to agree on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which customer journeys must work before recovery is declared complete?&lt;/li&gt;
&lt;li&gt;How much data loss is acceptable? This informs the recovery point objective, or RPO.&lt;/li&gt;
&lt;li&gt;How long can the service remain unavailable? This informs the recovery time objective, or RTO.&lt;/li&gt;
&lt;li&gt;Who can access backups and keys if the usual operator is unavailable?&lt;/li&gt;
&lt;li&gt;Who owns the decision to resume writes?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Measure retrieval, provisioning, restore, validation and application readiness separately. A stopwatch around &lt;code&gt;pg_restore&lt;/code&gt; alone does not measure the full recovery experience.&lt;/p&gt;

&lt;p&gt;Keep a dated record with the backup identifier, environment, tool versions, checks, timings, failures and follow-up owner. Redact sensitive information before sharing it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The target isn't “a backup exists.” The target is a recovery process your team has evidence for.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What would you check first after a database restore: a row count, an application login, or the customer journey that makes the business money—and why?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Draft prepared with AI support. The synthetic-data walkthrough was checked in an isolated PostgreSQL 18 cluster during draft preparation. Author review and environment-specific testing are still required before publication.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;#PostgreSQL #Linux #DevOps #Beginners&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>beginners</category>
      <category>linux</category>
      <category>devops</category>
    </item>
    <item>
      <title>What Evidence Makes You Trust a Backup?</title>
      <dc:creator>Umer Amin Durrani</dc:creator>
      <pubDate>Sat, 07 Nov 2026 08:56:18 +0000</pubDate>
      <link>https://dev.to/umeramindurrani/what-evidence-makes-you-trust-a-backup-39m0</link>
      <guid>https://dev.to/umeramindurrani/what-evidence-makes-you-trust-a-backup-39m0</guid>
      <description>&lt;p&gt;You know the friend who says, “I'm five minutes away,” while still looking for their keys?&lt;/p&gt;

&lt;p&gt;Sometimes a backup dashboard has that same energy.&lt;/p&gt;

&lt;p&gt;“Completed successfully” sounds like the whole journey. Depending on the job, it may only describe one stage.&lt;/p&gt;

&lt;p&gt;That doesn't make the dashboard useless. It means we should ask what its green tick actually measures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four different kinds of confidence
&lt;/h2&gt;

&lt;p&gt;Here is a discussion framework, not an industry certification scheme:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Evidence&lt;/th&gt;
&lt;th&gt;What it helps establish&lt;/th&gt;
&lt;th&gt;What remains open&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A recent file exists&lt;/td&gt;
&lt;td&gt;An artefact is present&lt;/td&gt;
&lt;td&gt;Is it complete, trusted and accessible when needed?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The backup operation succeeded&lt;/td&gt;
&lt;td&gt;The operation met its configured success criteria&lt;/td&gt;
&lt;td&gt;Can we restore it into the required environment?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A restore exercise passed&lt;/td&gt;
&lt;td&gt;That tested restoration worked under those conditions&lt;/td&gt;
&lt;td&gt;Can the application and its dependencies operate?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A recovery drill met its targets&lt;/td&gt;
&lt;td&gt;The tested service recovery met defined criteria&lt;/td&gt;
&lt;td&gt;Will changed infrastructure or a different incident break the assumptions?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The distinction matters because a backup tool, a database administrator and a customer may all mean different things by “working.”&lt;/p&gt;

&lt;p&gt;The customer probably isn't interested in a screenshot of the cron job. Fair enough, honestly.&lt;/p&gt;

&lt;h2&gt;
  
  
  My favourite question for a recovery meeting
&lt;/h2&gt;

&lt;p&gt;Not “Do we have backups?”&lt;/p&gt;

&lt;p&gt;Try:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“What is the most recent recovery evidence, and what did that exercise leave untested?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That question makes room for an honest answer. Maybe the data restored correctly, but nobody tested the application role. Maybe the files are solid, but retrieval depends on one person's account.&lt;/p&gt;

&lt;p&gt;Those are useful findings. They are not reasons to roast whoever ran the drill.&lt;/p&gt;

&lt;p&gt;A practice session that reveals a missing key is doing its job. Finding it during the outage is the inconvenient sequel.&lt;/p&gt;

&lt;h2&gt;
  
  
  A small action worth trying
&lt;/h2&gt;

&lt;p&gt;At the next review, choose one important user journey. Write down how you would prove it works after restoration, which dependencies it requires and who can run that check.&lt;/p&gt;

&lt;p&gt;No dramatic transformation programme needed. Just make one assumption visible.&lt;/p&gt;

&lt;p&gt;For PostgreSQL specifically, the official &lt;a href="https://www.postgresql.org/docs/18/backup.html" rel="noopener noreferrer"&gt;backup and restore chapter&lt;/a&gt; is a useful starting point for understanding the different approaches.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which recovery assumption has surprised you most: permissions, missing files, unavailable credentials, external integrations—or something completely different?&lt;/strong&gt; Share the lesson without exposing customer data or internal credentials.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Draft prepared with AI support. The examples are discussion scenarios, not claimed personal incidents.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;#Discuss #DevOps #Database #Productivity&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>devops</category>
      <category>database</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Before You Run That AI-Generated Bash Script, Read This</title>
      <dc:creator>Umer Amin Durrani</dc:creator>
      <pubDate>Sat, 07 Nov 2026 08:50:46 +0000</pubDate>
      <link>https://dev.to/umeramindurrani/before-you-run-that-ai-generated-bash-script-read-this-1908</link>
      <guid>https://dev.to/umeramindurrani/before-you-run-that-ai-generated-bash-script-read-this-1908</guid>
      <description>&lt;p&gt;The assistant writes a Bash script in twelve seconds.&lt;/p&gt;

&lt;p&gt;The script has comments, a progress message and a final line saying “Done!”&lt;/p&gt;

&lt;p&gt;Looks professional, mate. Unfortunately, confidence is not a permission boundary.&lt;/p&gt;

&lt;p&gt;Before executing it, ask one question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What can this script change, and how do I know those are the things I intended?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You don't need to distrust every AI-generated line. You need a review process that doesn't depend on the assistant sounding sensible.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Translate the request into a bounded task
&lt;/h2&gt;

&lt;p&gt;“Clean up my server” is not a specification.&lt;/p&gt;

&lt;p&gt;A more reviewable request would be:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;List regular &lt;code&gt;.log&lt;/code&gt; files older than 14 days inside one specified lab directory. Do not delete, upload, change ownership or follow symbolic-link directories. Print the candidates for human review.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now you have observable boundaries. Directory, age, file type and permitted action are explicit.&lt;/p&gt;

&lt;p&gt;This is the software equivalent of telling someone which cupboard to tidy instead of saying, “Sort the house out.” Your passport should not become collateral damage.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Review four things before the syntax
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Target:&lt;/strong&gt; Does the path resolve to the intended directory? Are remote host and account correct?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Authority:&lt;/strong&gt; Which user executes the script? Can it write outside the target, access secrets or invoke privileged commands?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Inputs:&lt;/strong&gt; Can filenames, environment variables or untrusted text alter the command's meaning?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Effects:&lt;/strong&gt; Does it delete, install, change permissions, send data, stop services or alter databases?&lt;/p&gt;

&lt;p&gt;A syntactically valid command can still act on the wrong environment. Shell linting cannot decide your business intent for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Begin with inspection, not modification
&lt;/h2&gt;

&lt;p&gt;This Bash example only lists candidates. It assumes &lt;strong&gt;GNU find&lt;/strong&gt; on a Linux lab machine:&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;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nv"&gt;TARGET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;:?Usage:&lt;span class="p"&gt; inspect-logs.sh /path/to/lab-logs&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TARGET&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TARGET&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s\n'&lt;/span&gt; &lt;span class="s1"&gt;'Choose an existing, non-symlink lab directory.'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nv"&gt;TARGET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;realpath&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TARGET&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TARGET&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; / &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s\n'&lt;/span&gt; &lt;span class="s1"&gt;'The filesystem root is not an acceptable target.'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'Inspection only. Target: %q\n'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TARGET&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
find &lt;span class="nt"&gt;-P&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TARGET&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-xdev&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; f &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'*.log'&lt;/span&gt; &lt;span class="nt"&gt;-mtime&lt;/span&gt; +14 &lt;span class="nt"&gt;-print0&lt;/span&gt; |
  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt; candidate&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'Candidate: %q\n'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$candidate&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a review exercise, not a containment mechanism. A filesystem can change during inspection; path validation alone does not prevent races. &lt;code&gt;-xdev&lt;/code&gt; also intentionally avoids descending into other mounted filesystems. GNU &lt;code&gt;find&lt;/code&gt; age tests use their documented rounding rules—“older than 14 days” needs a precise definition if a retention policy depends on it.&lt;/p&gt;

&lt;p&gt;There is no deletion step hidden at the end. Inspect first; design the mutation separately if it is actually required.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Check syntax and common shell mistakes
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bash &lt;span class="nt"&gt;-n&lt;/span&gt; inspect-logs.sh
shellcheck inspect-logs.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first checks Bash syntax without executing the script. ShellCheck can identify many common shell issues. Neither proves the script is safe or appropriate for your environment. &lt;a href="https://www.shellcheck.net/" rel="noopener noreferrer"&gt;ShellCheck project&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Use a disposable directory with ordinary files, spaces in filenames, unexpected names, a symbolic link and a file that should not match. Decide the expected candidate list before running the script.&lt;/p&gt;

&lt;p&gt;That makes the result something you can compare, rather than something you can merely admire.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. A prompt is not a security control
&lt;/h2&gt;

&lt;p&gt;An AI assistant may read logs, pages or documents containing instructions you did not author. That makes the distinction between data and instructions important. Prompt wording alone should not be your enforcement layer. &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/LLM_Prompt_Injection_Prevention_Cheat_Sheet.html" rel="noopener noreferrer"&gt;OWASP prompt-injection guidance&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Put limits in the execution environment: restricted credentials, bounded tools and explicit approval for consequential actions. The model proposes; the surrounding system decides what is permitted.&lt;/p&gt;

&lt;p&gt;Also: adding &lt;code&gt;sudo&lt;/code&gt; because a command failed is not troubleshooting. It's changing the size of the mistake you can make.&lt;/p&gt;

&lt;h2&gt;
  
  
  The habit worth keeping
&lt;/h2&gt;

&lt;p&gt;Before execution, explain the script in your own words, identify every write or network operation, and describe how you'll verify the result.&lt;/p&gt;

&lt;p&gt;If you cannot do that yet, ask for a smaller script or a read-only version. There is no shame in needing an explanation. The server does not award bravery points.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the first thing you inspect in an unfamiliar shell script: paths, privilege, network calls, quoting—or something else?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Draft prepared with AI support. The illustrative script passed Bash syntax checking and a disposable-file fixture during draft preparation. ShellCheck and author environment-specific review remain outstanding.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;#Linux #Bash #AI #Security&lt;/p&gt;

</description>
      <category>linux</category>
      <category>bash</category>
      <category>ai</category>
      <category>security</category>
    </item>
    <item>
      <title>Which Commands Should an AI Agent Never Run Without Your Approval?</title>
      <dc:creator>Umer Amin Durrani</dc:creator>
      <pubDate>Sat, 07 Nov 2026 08:48:26 +0000</pubDate>
      <link>https://dev.to/umeramindurrani/which-commands-should-an-ai-agent-never-run-without-your-approval-3ph1</link>
      <guid>https://dev.to/umeramindurrani/which-commands-should-an-ai-agent-never-run-without-your-approval-3ph1</guid>
      <description>&lt;p&gt;“Are you sure?”&lt;/p&gt;

&lt;p&gt;Yes, bro. About what, exactly?&lt;/p&gt;

&lt;p&gt;A confirmation button isn't much help if the user cannot see the action, destination or likely effect.&lt;/p&gt;

&lt;p&gt;As assistants gain tools, the interesting question isn't whether they can run commands. It's &lt;strong&gt;which decisions we are comfortable delegating, under which conditions&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't classify risk by how short the command looks
&lt;/h2&gt;

&lt;p&gt;A long query might only read a local test table. A tiny command might change a production permission.&lt;/p&gt;

&lt;p&gt;Likewise, “read-only” does not always mean harmless: reading a credential file and sending its contents somewhere can expose a secret without changing the original file.&lt;/p&gt;

&lt;p&gt;I would start an approval design with these questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which environment is affected?&lt;/li&gt;
&lt;li&gt;Is the action reversible through an ordinary, tested process?&lt;/li&gt;
&lt;li&gt;Could it expose confidential data?&lt;/li&gt;
&lt;li&gt;Does it alter access, billing, availability or persisted records?&lt;/li&gt;
&lt;li&gt;Is the target bounded, or can it expand unexpectedly?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A proposed decision table
&lt;/h2&gt;

&lt;p&gt;This is a starting policy to adapt, not a universal permission standard:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Example action&lt;/th&gt;
&lt;th&gt;Possible treatment&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Read synthetic lab logs&lt;/td&gt;
&lt;td&gt;Allow within a scoped tool&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inspect production service health&lt;/td&gt;
&lt;td&gt;Allow only through approved, limited access&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prepare a deployment diff&lt;/td&gt;
&lt;td&gt;Allow preparation; review before applying&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Change production access rules&lt;/td&gt;
&lt;td&gt;Require specific human approval&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delete retained customer records&lt;/td&gt;
&lt;td&gt;Require the authorised workflow and explicit approval&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Send logs to an external service&lt;/td&gt;
&lt;td&gt;Review the contents, destination and data-sharing permission&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;OWASP's &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/AI_Agent_Security_Cheat_Sheet.html" rel="noopener noreferrer"&gt;AI Agent Security guidance&lt;/a&gt; discusses scoped tools and human oversight. The practical challenge is turning those principles into permissions your system actually enforces.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make approval a decision, not a reflex
&lt;/h2&gt;

&lt;p&gt;A useful request would say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Apply this reviewed configuration change to the staging service. It changes these two values. The rollback is this previous configuration.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That gives someone a decision they can inspect.&lt;/p&gt;

&lt;p&gt;Compare it with “Proceed?” after a wall of terminal output. That's less informed approval and more an endurance test.&lt;/p&gt;

&lt;p&gt;I would also bind approval to the reviewed action. If the target, payload or permissions change, the old approval should not become a blank cheque.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where would you draw the boundary for your own team: what can an agent execute independently, and what must always return to a human?&lt;/strong&gt; A concrete example is more useful than “never trust AI” or “automate everything.”&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Draft prepared with AI support. The table is an illustrative policy discussion, not a record of a deployed access-control system.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;#AI #Security #DevOps #Discuss&lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>devops</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Deployment Rollback Gets Complicated When the Database Has Moved On</title>
      <dc:creator>Umer Amin Durrani</dc:creator>
      <pubDate>Sat, 07 Nov 2026 08:47:04 +0000</pubDate>
      <link>https://dev.to/umeramindurrani/deployment-rollback-gets-complicated-when-the-database-has-moved-on-1o</link>
      <guid>https://dev.to/umeramindurrani/deployment-rollback-gets-complicated-when-the-database-has-moved-on-1o</guid>
      <description>&lt;p&gt;“Just roll it back.”&lt;/p&gt;

&lt;p&gt;A beautiful sentence. Four words. Very relaxing.&lt;/p&gt;

&lt;p&gt;Then someone asks whether the previous application still understands the new database schema, and suddenly everyone's tea is going cold.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rolling back an application release is not necessarily the same as restoring the whole system to an earlier state.&lt;/strong&gt; Writes, migrations, jobs and external effects may have continued after deployment.&lt;/p&gt;

&lt;p&gt;Let's work through an illustrative Django application. No customer incident or measured outcome is being claimed here.&lt;/p&gt;

&lt;h2&gt;
  
  
  The innocent-looking change
&lt;/h2&gt;

&lt;p&gt;Suppose a customer table has a &lt;code&gt;full_name&lt;/code&gt; column. A new release introduces separate &lt;code&gt;given_name&lt;/code&gt; and &lt;code&gt;family_name&lt;/code&gt; fields.&lt;/p&gt;

&lt;p&gt;A direct replacement sounds neat:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Remove &lt;code&gt;full_name&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add the new fields.&lt;/li&gt;
&lt;li&gt;Deploy the new application.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But an older application instance may still read &lt;code&gt;full_name&lt;/code&gt;. A worker might also be processing jobs created by the previous version.&lt;/p&gt;

&lt;p&gt;Now your deployment is a compatibility problem, not just a file replacement.&lt;/p&gt;

&lt;p&gt;And real names do not always split cleanly into two fields. The product assumption needs review before the migration gets anywhere near a database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Define a compatibility window
&lt;/h2&gt;

&lt;p&gt;One approach is to separate expansion from removal:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stage&lt;/th&gt;
&lt;th&gt;Database shape&lt;/th&gt;
&lt;th&gt;Application behaviour&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Expand&lt;/td&gt;
&lt;td&gt;Keep the old field; add new fields&lt;/td&gt;
&lt;td&gt;Existing release still operates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Transition&lt;/td&gt;
&lt;td&gt;Both representations exist&lt;/td&gt;
&lt;td&gt;New code uses a defined synchronisation and fallback strategy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Verify&lt;/td&gt;
&lt;td&gt;Reconciliation and behaviour checks pass&lt;/td&gt;
&lt;td&gt;All active services and jobs support the new representation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Contract&lt;/td&gt;
&lt;td&gt;Remove the old field when safe&lt;/td&gt;
&lt;td&gt;Returning to the old release may no longer be supported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This is a proposed design pattern, not a promise that every field migration can be handled this way.&lt;/p&gt;

&lt;p&gt;The transition stage deserves most of the thinking. What happens if one write succeeds and another fails? Which field is authoritative? How will old and new application instances coexist? Can a backfill be resumed without corrupting later updates?&lt;/p&gt;

&lt;p&gt;“Write both” is a starting thought, not a complete consistency design.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Django migration isn't automatically reversible
&lt;/h2&gt;

&lt;p&gt;Framework support is useful, but it does not recover information that was discarded.&lt;/p&gt;

&lt;p&gt;Django supports migration dependencies and reverse operations, while some operations or custom data migrations can be irreversible. Review what your specific migration does rather than assuming a reverse command makes the business change safe. &lt;a href="https://docs.djangoproject.com/en/5.2/topics/migrations/" rel="noopener noreferrer"&gt;Django migration documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before release, I would want the team to answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can the previous application version run against the expanded schema?&lt;/li&gt;
&lt;li&gt;Does the backfill preserve the original values needed for recovery?&lt;/li&gt;
&lt;li&gt;Can old workers consume new jobs, or do queues need version-aware handling?&lt;/li&gt;
&lt;li&gt;Which step ends the compatibility window?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last question is the one that tends to hide behind “we'll tidy it later.” Later has an impressive backlog.&lt;/p&gt;

&lt;h2&gt;
  
  
  Separate the rollback decisions
&lt;/h2&gt;

&lt;p&gt;There are several different actions people may mean:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Application rollback:&lt;/strong&gt; route traffic to a previous application artefact.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configuration rollback:&lt;/strong&gt; restore previously reviewed settings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Migration reversal:&lt;/strong&gt; execute a specific reverse schema or data operation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Database recovery:&lt;/strong&gt; restore data from a backup or recovery point.&lt;/p&gt;

&lt;p&gt;These actions have different consequences. Database recovery can lose legitimate writes made after the recovery point and may disagree with external systems that already acted on those writes.&lt;/p&gt;

&lt;p&gt;A payment provider is unlikely to say, “Ah, you rolled back your database? No worries, we'll forget that transaction too.”&lt;/p&gt;

&lt;h2&gt;
  
  
  Rehearse a journey, not just a deployment command
&lt;/h2&gt;

&lt;p&gt;For a controlled staging exercise:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start with the previous release and synthetic data.&lt;/li&gt;
&lt;li&gt;Apply the expansion step.&lt;/li&gt;
&lt;li&gt;Exercise old and new application behaviour under the planned coexistence model.&lt;/li&gt;
&lt;li&gt;Create representative new records and queued jobs.&lt;/li&gt;
&lt;li&gt;Return application traffic to the earlier version.&lt;/li&gt;
&lt;li&gt;Check reads, writes, authorisation and job processing.&lt;/li&gt;
&lt;li&gt;Record exactly which actions are safe and which require a different recovery procedure.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Use acceptance criteria defined before the exercise. “No obvious errors” is a mood, not a test case.&lt;/p&gt;

&lt;p&gt;Google's discussion of &lt;a href="https://sre.google/sre-book/reliable-product-launches/" rel="noopener noreferrer"&gt;reliable product launches&lt;/a&gt; is useful background on planning and managing launch risk. The specific compatibility matrix above is an illustrative design to adapt to your own system.&lt;/p&gt;

&lt;h2&gt;
  
  
  The useful release question
&lt;/h2&gt;

&lt;p&gt;Instead of asking only, “How do we deploy?” ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“After each step, which earlier state can we safely return to—and what evidence supports that?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That gives the Technical PM a real coordination task: align application engineers, database owners, operations and product decision-makers around the same recovery options.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which dependency makes rollback hardest in your environment: schema, background jobs, configuration, third-party APIs or data written during the release?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Draft prepared with AI support. The migration scenario and release plan are illustrative, not a claimed production implementation.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;#DevOps #Architecture #Database #Django&lt;/p&gt;

</description>
      <category>devops</category>
      <category>architecture</category>
      <category>django</category>
      <category>database</category>
    </item>
    <item>
      <title>When Is Rolling Forward Safer Than Rolling Back?</title>
      <dc:creator>Umer Amin Durrani</dc:creator>
      <pubDate>Sat, 07 Nov 2026 08:46:09 +0000</pubDate>
      <link>https://dev.to/umeramindurrani/when-is-rolling-forward-safer-than-rolling-back-473p</link>
      <guid>https://dev.to/umeramindurrani/when-is-rolling-forward-safer-than-rolling-back-473p</guid>
      <description>&lt;p&gt;You take a wrong turn. Your passenger says, “Just reverse.”&lt;/p&gt;

&lt;p&gt;Solid advice in an empty car park. Slightly different situation on a busy flyover.&lt;/p&gt;

&lt;p&gt;A software rollback also depends on what happened after the turn.&lt;/p&gt;

&lt;h2&gt;
  
  
  The previous release isn't automatically the safer release
&lt;/h2&gt;

&lt;p&gt;Imagine that a new application version has written records the earlier version cannot interpret.&lt;/p&gt;

&lt;p&gt;Returning to the previous binary might be quick. Returning to safe behaviour might not be.&lt;/p&gt;

&lt;p&gt;On the other hand, a rushed forward fix can introduce another unknown. “I can patch it in five minutes” belongs in the same category as “I'm leaving the house now”: useful information, but worth checking.&lt;/p&gt;

&lt;h2&gt;
  
  
  A decision framework I would bring to the incident
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;Why it matters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Does the previous version work with current persisted state?&lt;/td&gt;
&lt;td&gt;Compatibility can rule out an ordinary rollback&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Can we contain the effect by disabling one feature?&lt;/td&gt;
&lt;td&gt;A smaller action may reduce impact without a full release&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Is the proposed forward fix narrow and verifiable?&lt;/td&gt;
&lt;td&gt;Another speculative deployment can increase uncertainty&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Are external systems already acting on the new data?&lt;/td&gt;
&lt;td&gt;Reverting local state may not undo those effects&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Who can authorise the recovery choice?&lt;/td&gt;
&lt;td&gt;Parallel uncoordinated changes make diagnosis harder&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;There is no clever slogan that replaces these answers.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Technical PM contribution
&lt;/h2&gt;

&lt;p&gt;During an incident, the useful job is not to shout “rollback” louder than everyone else.&lt;/p&gt;

&lt;p&gt;Make the alternatives visible. Capture what is known, who is investigating each unknown and when the team will reassess. Keep customer communication aligned with the actual state of recovery.&lt;/p&gt;

&lt;p&gt;Afterwards, turn the uncertainty into a release improvement. If nobody knew whether the old version could read the current schema, add that check to the next release plan.&lt;/p&gt;

&lt;p&gt;GitHub's &lt;a href="https://docs.github.com/en/actions/reference/workflows-and-actions/deployments-and-environments" rel="noopener noreferrer"&gt;deployment environment controls&lt;/a&gt; can help enforce certain deployment gates where available. They do not decide whether an old application is compatible with your current data; that remains a system-specific question.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What fact would make you reject a rollback and choose a forward fix instead?&lt;/strong&gt; I'd love a concrete scenario, with the sensitive details removed.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Draft prepared with AI support. The scenario is hypothetical and the decision table is a discussion aid.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Discuss #DevOps #Architecture #Productivity
&lt;/h1&gt;

</description>
      <category>discuss</category>
      <category>devops</category>
      <category>architecture</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How to Write Acceptance Criteria for AI Features That Actually Mean Something</title>
      <dc:creator>Umer Amin Durrani</dc:creator>
      <pubDate>Sat, 07 Nov 2026 08:44:22 +0000</pubDate>
      <link>https://dev.to/umeramindurrani/how-to-write-acceptance-criteria-for-ai-features-that-actually-mean-something-1n2d</link>
      <guid>https://dev.to/umeramindurrani/how-to-write-acceptance-criteria-for-ai-features-that-actually-mean-something-1n2d</guid>
      <description>&lt;p&gt;“The AI should answer accurately.”&lt;/p&gt;

&lt;p&gt;Great. The food should also taste nice. We still need to know what we're ordering.&lt;/p&gt;

&lt;p&gt;A polished demo can make an AI feature feel finished before the team has agreed on what success means.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Useful acceptance criteria describe the behaviour, context, evidence and failure boundaries—not just how convincing the answer sounds.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's use an illustrative support assistant for a small online shop. This is a proposed evaluation design, not a claim about a deployed product.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with the customer's task
&lt;/h2&gt;

&lt;p&gt;The customer wants to understand a return policy or find out where an order is.&lt;/p&gt;

&lt;p&gt;Those tasks require different capabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A policy answer may be grounded in approved documents.&lt;/li&gt;
&lt;li&gt;An order-status answer needs current order data and an authorised identity.&lt;/li&gt;
&lt;li&gt;A refund changes business state and may require a separate approval process.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Putting all three behind one chat box does not make them the same requirement.&lt;/p&gt;

&lt;p&gt;“It's just a chatbot” has done some heavy lifting in software meetings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Replace adjectives with observable checks
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Vague requirement&lt;/th&gt;
&lt;th&gt;More useful proposed criterion&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Give accurate policy answers&lt;/td&gt;
&lt;td&gt;Use the current approved policy and identify the relevant source; do not invent an exception&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Handle missing information&lt;/td&gt;
&lt;td&gt;Ask for the missing detail or explain the limitation rather than guessing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Respect privacy&lt;/td&gt;
&lt;td&gt;Do not reveal an order's information when the requesting user is not authorised to access it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Escalate when needed&lt;/td&gt;
&lt;td&gt;Offer the defined human handoff when the task is outside the assistant's permitted scope&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Process refunds&lt;/td&gt;
&lt;td&gt;Prepare the request but do not execute a refund without the required approval&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These are still a starting point. “Current approved policy” needs a source owner, version and update process. “Human handoff” needs a destination that someone actually monitors.&lt;/p&gt;

&lt;p&gt;Otherwise, escalation is just the bot politely placing your problem in a decorative cupboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build a small evaluation set before arguing about the model
&lt;/h2&gt;

&lt;p&gt;Start with a deliberately limited set of synthetic examples that cover different failure modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A straightforward question with an answer in the policy.&lt;/li&gt;
&lt;li&gt;A question whose answer is absent.&lt;/li&gt;
&lt;li&gt;An ambiguous request that needs clarification.&lt;/li&gt;
&lt;li&gt;A request involving another customer's information.&lt;/li&gt;
&lt;li&gt;A stale document conflicting with an approved update.&lt;/li&gt;
&lt;li&gt;A request to ignore the policy or execute an unauthorised action.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For each case, write down the acceptable outcome and unacceptable behaviour &lt;strong&gt;before&lt;/strong&gt; generating the response. Keep some representative cases separate from prompt development so you are not only checking examples the team has tuned against.&lt;/p&gt;

&lt;p&gt;Anthropic's &lt;a href="https://www.anthropic.com/research/demystifying-evals-for-ai-agents" rel="noopener noreferrer"&gt;agent-evaluation guide&lt;/a&gt; is useful reading on evaluation structure and different kinds of graders. Our shop-assistant cases are an original illustrative test design, not results from that guide.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use several checks, not one impressive percentage
&lt;/h2&gt;

&lt;p&gt;A response can be fluent and still expose private information. It can quote a policy correctly while acting on the wrong order.&lt;/p&gt;

&lt;p&gt;Track different dimensions separately:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer quality:&lt;/strong&gt; Is the response supported by the approved source?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Task behaviour:&lt;/strong&gt; Did the assistant ask for clarification or offer a handoff when required?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Action safety:&lt;/strong&gt; Did it stay within its tool permissions and approval boundaries?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Operational behaviour:&lt;/strong&gt; What happened to latency, timeouts and provider failures under the tested conditions?&lt;/p&gt;

&lt;p&gt;A small test set cannot establish a precise population-wide failure rate. Report counts, cases and limitations rather than dressing a handful of examples up as scientific certainty.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make action boundaries enforceable
&lt;/h2&gt;

&lt;p&gt;If the assistant is not permitted to issue a refund, don't rely only on “never issue refunds” in its prompt.&lt;/p&gt;

&lt;p&gt;The surrounding tools and authorisation layer should enforce what it can do. OWASP's &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/AI_Agent_Security_Cheat_Sheet.html" rel="noopener noreferrer"&gt;AI Agent Security guidance&lt;/a&gt; discusses this separation between agent behaviour and system controls.&lt;/p&gt;

&lt;p&gt;For the shop example, the assistant could prepare a structured refund request. An authorised workflow validates the order, amount, eligibility and approval before executing anything.&lt;/p&gt;

&lt;p&gt;Same customer conversation. Very different risk boundary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Define the release decision
&lt;/h2&gt;

&lt;p&gt;The team should decide in advance which failures block a release, which require restricted availability and which can be monitored with a named follow-up owner.&lt;/p&gt;

&lt;p&gt;Document the model identifier, prompt version, source snapshot, tool configuration and evaluation conditions. Reassess when those inputs materially change.&lt;/p&gt;

&lt;p&gt;The Technical PM doesn't need to pretend to be the model researcher. The job is to make sure product intent, engineering behaviour, security boundaries and release evidence describe the same feature.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you could add one acceptance criterion to an AI feature tomorrow, would it concern answer quality, privacy, escalation or tool permissions? Why that one?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Draft prepared with AI support. All scenarios and evaluation criteria are illustrative; no benchmark result is claimed.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  AI #Testing #Architecture #Productivity
&lt;/h1&gt;

</description>
      <category>ai</category>
      <category>testing</category>
      <category>architecture</category>
      <category>eventdriven</category>
    </item>
    <item>
      <title>What Does 'The AI Works' Actually Mean?</title>
      <dc:creator>Umer Amin Durrani</dc:creator>
      <pubDate>Sat, 07 Nov 2026 08:42:57 +0000</pubDate>
      <link>https://dev.to/umeramindurrani/what-does-the-ai-works-actually-mean-ipe</link>
      <guid>https://dev.to/umeramindurrani/what-does-the-ai-works-actually-mean-ipe</guid>
      <description>&lt;p&gt;The demo answers one question beautifully.&lt;/p&gt;

&lt;p&gt;Someone says, “It works.”&lt;/p&gt;

&lt;p&gt;The room nods. A slide gets a green tick. Somewhere, a requirement quietly escapes through the window.&lt;/p&gt;

&lt;p&gt;I'm interested in the next question: &lt;strong&gt;works for which task, for whom, and under what conditions?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A chat box can hide several different products
&lt;/h2&gt;

&lt;p&gt;An assistant that summarises a public document is different from one that reads customer records. Both are different from one that can change those records.&lt;/p&gt;

&lt;p&gt;They might share the same interface. Their acceptance criteria should not be interchangeable.&lt;/p&gt;

&lt;p&gt;Think of a kitchen knife and a plastic spoon. Both live in the cutlery drawer. We do not run identical safety tests because they have similar storage arrangements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four claims to separate
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;“It produced a plausible answer.”&lt;/strong&gt;&lt;br&gt;
That describes the appearance of one output.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;“It answered these representative cases acceptably.”&lt;/strong&gt;&lt;br&gt;
Now we have a test set, conditions and criteria to inspect.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;“It stayed inside its permissions when the request was hostile or ambiguous.”&lt;/strong&gt;&lt;br&gt;
Now we are checking behaviour that a friendly demo may never exercise.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;“It continues to meet our service expectations after changes.”&lt;/strong&gt;&lt;br&gt;
Now we need monitoring and repeatable evaluation, not only a memorable launch-day conversation.&lt;/p&gt;

&lt;p&gt;None of these statements automatically proves the next one.&lt;/p&gt;

&lt;h2&gt;
  
  
  An exercise for the next product meeting
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://umer-amin.vercel.app/" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ask everyone to finish this sentence independently:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“We should not release this assistant if it ______.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A developer might say “times out on common queries.” Product might say “cannot complete the customer's task.” Security might say “reveals another user's information.” Operations might say “fails without a usable fallback.”&lt;/p&gt;

&lt;p&gt;That disagreement is useful. You have discovered different expectations while everyone still has time to do something about them.&lt;/p&gt;

&lt;p&gt;It is much cheaper than discovering the same disagreement through an angry support ticket.&lt;/p&gt;

&lt;p&gt;For evaluation background, see &lt;a href="https://www.anthropic.com/research/demystifying-evals-for-ai-agents" rel="noopener noreferrer"&gt;Anthropic's discussion of agent evals&lt;/a&gt;. An evaluation needs to match your task; copying somebody else's benchmark score is not a substitute for defining your own release question.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is one AI failure your team would treat as a release blocker, even if the assistant gives excellent answers most of the time?&lt;/strong&gt; Specific examples welcome; confidential details can stay off the internet.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Draft prepared with AI support. The meeting and assistant examples are hypothetical, not claimed firsthand events.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;#AI #Discuss #Testing #Productivity&lt;/p&gt;

</description>
      <category>ai</category>
      <category>discuss</category>
      <category>testing</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
