<?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: mars70s</title>
    <description>The latest articles on DEV Community by mars70s (@mars70s).</description>
    <link>https://dev.to/mars70s</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%2F4132952%2F244cd4d2-ff3b-4435-be17-beea129b6e0d.png</url>
      <title>DEV Community: mars70s</title>
      <link>https://dev.to/mars70s</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mars70s"/>
    <language>en</language>
    <item>
      <title>We Had a Single Source of Truth—and Still Had Stale State</title>
      <dc:creator>mars70s</dc:creator>
      <pubDate>Mon, 12 Oct 2026 10:02:27 +0000</pubDate>
      <link>https://dev.to/mars70s/we-had-a-single-source-of-truth-and-still-had-stale-state-227h</link>
      <guid>https://dev.to/mars70s/we-had-a-single-source-of-truth-and-still-had-stale-state-227h</guid>
      <description>&lt;p&gt;We had already chosen a Single Source of Truth.&lt;/p&gt;

&lt;p&gt;The canonical state file was correct.&lt;/p&gt;

&lt;p&gt;Later work updated that canonical state.&lt;/p&gt;

&lt;p&gt;And yet another document still contained an obsolete view of the current work.&lt;/p&gt;

&lt;p&gt;At first glance, this looks like a simple documentation mistake:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Someone forgot to update a file.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The Git history showed something more useful.&lt;/p&gt;

&lt;p&gt;The stale copy was already inconsistent &lt;strong&gt;at the commit that introduced the Single Source of Truth rule&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Later updates did not create the inconsistency. They widened it.&lt;/p&gt;

&lt;p&gt;That distinction changed how I thought about the fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  The migration looked correct
&lt;/h2&gt;

&lt;p&gt;The repository used several documents to manage an ongoing technical-writing workflow.&lt;/p&gt;

&lt;p&gt;One of them, &lt;code&gt;active/WORK_STATUS.md&lt;/code&gt;, was selected as the sole mutable authority for current state.&lt;/p&gt;

&lt;p&gt;At the same time, a worker-instruction document, &lt;code&gt;AGENTS.md&lt;/code&gt;, was changed so that it explicitly said current state should not be duplicated there.&lt;/p&gt;

&lt;p&gt;Conceptually, the new rule was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WORK_STATUS owns current state.

AGENTS contains durable worker rules.

AGENTS should not duplicate mutable current state.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is a reasonable authority model.&lt;/p&gt;

&lt;p&gt;But the migration was incomplete.&lt;/p&gt;

&lt;p&gt;One section of &lt;code&gt;AGENTS.md&lt;/code&gt; had been cleaned up.&lt;/p&gt;

&lt;p&gt;Another section still contained state such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;current target = TOP-04
current work boundary = early evidence construction
formal draft work should not proceed yet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The problem was not only that those values existed in two places.&lt;/p&gt;

&lt;p&gt;They were already different.&lt;/p&gt;

&lt;p&gt;The canonical &lt;code&gt;WORK_STATUS.md&lt;/code&gt; had moved further ahead than the remaining state text in &lt;code&gt;AGENTS.md&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So the repository contained this contradiction:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AGENTS:
Do not duplicate current state here.

AGENTS, another section:
Here is the current state.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Later updates followed the new authority model
&lt;/h2&gt;

&lt;p&gt;After that migration, the workflow continued.&lt;/p&gt;

&lt;p&gt;The formal draft moved forward and was Human Approved.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;WORK_STATUS.md&lt;/code&gt; and related project documents were updated.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;AGENTS.md&lt;/code&gt; was not part of that particular state-update commit.&lt;/p&gt;

&lt;p&gt;That alone is not evidence of a problem.&lt;/p&gt;

&lt;p&gt;If &lt;code&gt;WORK_STATUS.md&lt;/code&gt; is the mutable state authority, updating the authority instead of every historical copy is exactly what the new model says to do.&lt;/p&gt;

&lt;p&gt;But because the old copy had not been removed during migration, the difference became more visible.&lt;/p&gt;

&lt;p&gt;The interesting part came later.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;AGENTS.md&lt;/code&gt; itself was edited several more times for unrelated policy changes.&lt;/p&gt;

&lt;p&gt;The obsolete state section still survived.&lt;/p&gt;

&lt;p&gt;So the persistence cannot be explained only as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;AGENTS was outside the write scope.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The file was opened and changed later.&lt;/p&gt;

&lt;p&gt;The stale section simply was not identified as part of the authority migration problem.&lt;/p&gt;

&lt;p&gt;That made the detection gap more important than the individual write scope.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Single Source of Truth was not the problem
&lt;/h2&gt;

&lt;p&gt;This case did not show that SSOT is ineffective.&lt;/p&gt;

&lt;p&gt;The canonical state did its job.&lt;/p&gt;

&lt;p&gt;The problem was migration completeness.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WORK_STATUS is now authoritative
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;does not automatically remove every older mutable copy.&lt;/p&gt;

&lt;p&gt;A migration has at least two sides:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Select the new authority.

2. Remove, convert, or explicitly retire the old mutable replicas.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If step 2 is incomplete, a stale copy can survive outside the canonical update path.&lt;/p&gt;

&lt;p&gt;That is especially easy to miss when the old copy appears inside a document that otherwise contains durable rules.&lt;/p&gt;

&lt;p&gt;A policy document can slowly become a mixed object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;durable rules
+
temporary current-state snapshot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once that happens, it becomes unclear which parts should change when project state changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The tempting fix was not the structural fix
&lt;/h2&gt;

&lt;p&gt;The easiest correction would have been:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TOP-04 → whatever the latest target is
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That would make the document look correct again.&lt;/p&gt;

&lt;p&gt;But it would preserve the same ownership problem.&lt;/p&gt;

&lt;p&gt;The next state transition could make the copy stale again.&lt;/p&gt;

&lt;p&gt;Instead, the relevant section was changed so that values such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;current target
next gate
evidence authority
per-item state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;were no longer duplicated there.&lt;/p&gt;

&lt;p&gt;The durable document now points back to the mutable authority.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before:

WORK_STATUS:
current target = X

AGENTS:
current target = X


After:

WORK_STATUS:
current target = X

AGENTS:
read current target from WORK_STATUS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fix was therefore not:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Update the old value.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It was:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Remove ownership of that value from the wrong document.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Bounded write scopes were not the villain
&lt;/h2&gt;

&lt;p&gt;There was another tempting explanation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Strict write scopes caused the stale state because nobody was allowed to touch the other file.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The Git history did not support that conclusion.&lt;/p&gt;

&lt;p&gt;A bounded change scope does something useful: it limits the files changed by a particular operation.&lt;/p&gt;

&lt;p&gt;What it does &lt;strong&gt;not&lt;/strong&gt; do is discover every pre-existing inconsistency outside that scope.&lt;/p&gt;

&lt;p&gt;Those are different properties.&lt;/p&gt;

&lt;p&gt;So a safer conclusion is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A bounded change scope can preserve a pre-existing inconsistency
without being the cause of that inconsistency.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That matters in tightly controlled Git workflows.&lt;/p&gt;

&lt;p&gt;“Only change the authorized files” is still a useful rule.&lt;/p&gt;

&lt;p&gt;It just should not be confused with a repository-wide semantic consistency check.&lt;/p&gt;

&lt;h2&gt;
  
  
  Syntax can be correct while document roles are wrong
&lt;/h2&gt;

&lt;p&gt;Nothing about this failure required broken Markdown or an invalid Git state.&lt;/p&gt;

&lt;p&gt;A document could be syntactically valid.&lt;/p&gt;

&lt;p&gt;The diff could be clean.&lt;/p&gt;

&lt;p&gt;The intended files could be the only files changed.&lt;/p&gt;

&lt;p&gt;The canonical state could be correct.&lt;/p&gt;

&lt;p&gt;And the repository could still contain a contradiction about &lt;strong&gt;which document owns current state&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That is a different type of invariant.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AGENTS must not retain duplicated mutable current-state values
when WORK_STATUS is the canonical mutable authority.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A normal diff or syntax check does not automatically establish that invariant.&lt;/p&gt;

&lt;p&gt;This does not mean every repository needs another giant validation framework.&lt;/p&gt;

&lt;p&gt;In this case, the useful lesson was much smaller:&lt;/p&gt;

&lt;p&gt;When converting a project to a Single Source of Truth, explicitly look for the old mutable copies once.&lt;/p&gt;

&lt;p&gt;Remove them, convert them into references, or mark them as historical.&lt;/p&gt;

&lt;p&gt;Then go back to building the actual thing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I took from the case
&lt;/h2&gt;

&lt;p&gt;My practical takeaway is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;An SSOT migration is not finished when the new authority is declared. It is finished when the old mutable replicas no longer compete with it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A few narrower lessons followed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Durable policy documents should avoid owning ephemeral project state when another file is authoritative.&lt;/li&gt;
&lt;li&gt;Updating a copied value is sometimes legitimate, especially for an explicitly subordinate summary.&lt;/li&gt;
&lt;li&gt;A bounded write scope protects scope; it does not repair unrelated existing inconsistencies.&lt;/li&gt;
&lt;li&gt;Cross-document semantic invariants are different from syntax and diff correctness.&lt;/li&gt;
&lt;li&gt;Sometimes the better fix is to remove state ownership rather than keep synchronizing copies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is one repository case, not evidence that every SSOT migration fails this way.&lt;/p&gt;

&lt;p&gt;It is also not an AI-specific failure.&lt;/p&gt;

&lt;p&gt;The mechanism is fundamentally about document authority, mutable state, and incomplete migration.&lt;/p&gt;

&lt;p&gt;The full case study includes the commit chronology, evidence boundaries, and what each commit does and does not establish:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://osiix.com/en/library/single-source-of-truth-stale-state.html" rel="noopener noreferrer"&gt;https://osiix.com/en/library/single-source-of-truth-stale-state.html&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;AI disclosure:&lt;/strong&gt; AI-assisted drafting and review tools were used during preparation. The underlying Git evidence, claim boundaries, corrections, and publication decision were reviewed by the author.&lt;/p&gt;

</description>
      <category>git</category>
      <category>devops</category>
      <category>documentation</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Six Git Checks After an AI-Assisted Change — And What They Cannot Guarantee</title>
      <dc:creator>mars70s</dc:creator>
      <pubDate>Thu, 08 Oct 2026 14:15:41 +0000</pubDate>
      <link>https://dev.to/mars70s/six-git-checks-after-an-ai-assisted-change-and-what-they-cannot-guarantee-260g</link>
      <guid>https://dev.to/mars70s/six-git-checks-after-an-ai-assisted-change-and-what-they-cannot-guarantee-260g</guid>
      <description>&lt;p&gt;A coding assistant changes the two files you asked it to edit. The diff looks reasonable. Is the next Git operation safe to proceed?&lt;/p&gt;

&lt;p&gt;Not necessarily. You might be in the wrong repository. An extra file might already be staged. The branch or configured push destination might have changed. Or the secret scanner might have failed to run at all.&lt;/p&gt;

&lt;p&gt;These are not necessarily mistakes in the generated code. They are mismatches between &lt;strong&gt;the workflow you authorized&lt;/strong&gt; and &lt;strong&gt;the Git state that actually exists&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I built a small, &lt;a href="https://github.com/mars70s/ai-workflow-safety-harness" rel="noopener noreferrer"&gt;public reference Git Safety Harness&lt;/a&gt; to check selected mismatches before a later operation. It is a PowerShell-based, fail-closed workflow control—not a sandbox, not an independent enforcement boundary, and not a guarantee of safe AI-generated code.&lt;/p&gt;

&lt;h2&gt;
  
  
  A two-file example
&lt;/h2&gt;

&lt;p&gt;Suppose the authorized work is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Edit &lt;code&gt;docs/article.md&lt;/code&gt; and &lt;code&gt;public/article.html&lt;/code&gt; in a particular repository.&lt;/li&gt;
&lt;li&gt;Stay on &lt;code&gt;main&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;For the next operation, stage only &lt;code&gt;docs/article.md&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Check the configured push URL for &lt;code&gt;origin&lt;/code&gt; against an explicitly approved URL.&lt;/li&gt;
&lt;li&gt;Run a staged-diff secret scan before any separately authorized push.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The harness does not invent these expectations. A human or an authorized workflow must define them first. The harness then compares selected observed Git state against them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Six checks, six different questions
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Question before proceeding&lt;/th&gt;
&lt;th&gt;Example of a reason to stop&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Repository Root&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Is this the intended Git repository?&lt;/td&gt;
&lt;td&gt;The command is running in another valid checkout.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Write Set&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Are observed tracked changes and non-ignored untracked paths within the allowed set?&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;README.md&lt;/code&gt; changed even though it was not authorized.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Stage Set&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Does the actual Git index contain only explicitly allowed staged paths?&lt;/td&gt;
&lt;td&gt;An unrelated file was staged earlier.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Branch&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Is the current symbolic branch the expected branch?&lt;/td&gt;
&lt;td&gt;HEAD is detached or the branch differs.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Push URL&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Does the selected remote have exactly one configured push URL, matching the approved URL?&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;origin&lt;/code&gt; points somewhere else, or has multiple push URLs.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Secret Scan&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Can Gitleaks run and accept the staged diff?&lt;/td&gt;
&lt;td&gt;Gitleaks is missing, cannot execute, or exits nonzero.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each question has a different failure mode. A PASS from one check does not substitute for the others.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Write Set and Stage Set are separate
&lt;/h3&gt;

&lt;p&gt;The Write Set asks which paths are allowed to change. The Stage Set asks a different question: which paths are allowed in the Git index for the next operation?&lt;/p&gt;

&lt;p&gt;The reference implementation reads the actual index with &lt;code&gt;git diff --cached --no-renames --name-only&lt;/code&gt; and compares staged paths with a separate allow-list. That is a separate comparison from the Write Set, which covers staged and unstaged tracked changes as well as non-ignored untracked paths, using its own allow-list.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: an allowed change, but an unapproved staged file
&lt;/h3&gt;

&lt;p&gt;The approved &lt;strong&gt;Write Set&lt;/strong&gt; contains both &lt;code&gt;docs/article.md&lt;/code&gt; and &lt;code&gt;public/article.html&lt;/code&gt;. The approved &lt;strong&gt;Stage Set&lt;/strong&gt; contains only &lt;code&gt;docs/article.md&lt;/code&gt;. Now imagine the following &lt;em&gt;hypothetical&lt;/em&gt; output, not a captured test transcript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git diff --cached --no-renames --name-only
docs/article.md
public/article.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both paths are allowed to &lt;strong&gt;change&lt;/strong&gt;, so their presence alone does not violate the Write Set. But &lt;code&gt;public/article.html&lt;/code&gt; is &lt;strong&gt;not&lt;/strong&gt; allowed in the index for this operation. The reference implementation treats this as a Stage Set mismatch and reports &lt;code&gt;GSH_STOP_STAGE_SET&lt;/code&gt; instead of accepting that staged state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What would happen next?&lt;/strong&gt; Consider two &lt;em&gt;hypothetical&lt;/em&gt; paths from this same Git state:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Without an effective Stage Set check:&lt;/strong&gt; If the workflow now runs &lt;code&gt;git commit&lt;/code&gt; without changing the index, &lt;strong&gt;both&lt;/strong&gt; &lt;code&gt;docs/article.md&lt;/code&gt; and &lt;code&gt;public/article.html&lt;/code&gt; are included in that commit. The second file was permitted to be edited, but was &lt;strong&gt;not authorized for this commit&lt;/strong&gt;. If that commit is later pushed under a separate authorization, the unintended change can reach the remote repository. Neither a commit nor a push is claimed to have occurred in this example.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;With the harness invoked and its exit respected:&lt;/strong&gt; The Stage Set mismatch triggers &lt;code&gt;GSH_STOP_STAGE_SET&lt;/code&gt; and a nonzero result. The calling workflow stops &lt;strong&gt;before its later commit or push action&lt;/strong&gt;, and the staged files remain for inspection—the harness does not silently unstage or repair them. A human can then decide whether to correct the staging, change the authorization, or stop the work.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This illustrates a workflow boundary, not a measured incident or a new test result. It also does &lt;strong&gt;not&lt;/strong&gt; mean that the harness itself blocks direct Git commands: if an actor bypasses the checked path, the local Layer-2 harness cannot enforce that stop.&lt;/p&gt;

&lt;p&gt;Likewise, checking a remote's &lt;em&gt;fetch&lt;/em&gt; address is not enough to establish its &lt;em&gt;push&lt;/em&gt; destination. The harness inspects push URLs and requires one exact match.&lt;/p&gt;

&lt;h2&gt;
  
  
  What fail-closed means here
&lt;/h2&gt;

&lt;p&gt;If a required state cannot be confirmed, the normal harness path stops rather than treating missing evidence as success.&lt;/p&gt;

&lt;p&gt;That includes a repository root that cannot be resolved, an unexpected branch, an unavailable Gitleaks executable, and a scanner execution failure. The validated PowerShell wrapper also treats invocation errors, a missing child exit status, and nonzero exits as failures.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;STOP is not an instruction for the assistant to silently repair the situation and continue.&lt;/strong&gt; It is a point for inspecting the observed state and obtaining any necessary human decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  What was actually tested?
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/mars70s/ai-workflow-safety-harness/blob/605f95cc2499120db8557f454312580fab2279a3/harnesses/git/docs/validation.md" rel="noopener noreferrer"&gt;commit-pinned Validation Record&lt;/a&gt; reports results for the identified implementation in documented Windows reference environments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;28/28&lt;/strong&gt; fail-closed cases passed: 14 under PowerShell 7 and 14 under Windows PowerShell 5.1.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;6/6&lt;/strong&gt; success-path cases passed: three under each shell, including a non-empty permitted staged diff scanned with real Gitleaks.&lt;/li&gt;
&lt;li&gt;The record identifies the source and test files using SHA-256 hashes and the versions used: Git 2.54.0.windows.1, PowerShell 7.6.5, Windows PowerShell 5.1.26100.9444, and Gitleaks 8.30.1. A later preserved revalidation used the same source/test identities with PowerShell 7.6.6.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The tests used synthetic local remotes and recorded bounded results for the identified implementation and environments. They did &lt;strong&gt;not&lt;/strong&gt; establish universal compatibility, unbypassability, or the safety of a later real-world push or deployment.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/mars70s/ai-workflow-safety-harness/tree/605f95cc2499120db8557f454312580fab2279a3/harnesses/git/docs/evidence/validation-20260919" rel="noopener noreferrer"&gt;Evidence Pack from that later revalidation&lt;/a&gt; preserves execution output, case results, exit codes, and a SHA-256 manifest. These are records of the later run, not the original run’s raw logs.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the harness cannot guarantee
&lt;/h2&gt;

&lt;p&gt;Three limits matter especially in AI-assisted workflows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Allowed does not mean correct.&lt;/strong&gt; A change inside &lt;code&gt;docs/article.md&lt;/code&gt; can still be technically or semantically wrong.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A local check can be bypassed.&lt;/strong&gt; If a person or agent can invoke raw Git, shell commands, or APIs outside the harness, the harness does not itself prohibit those paths. Independent restrictions belong outside this local workflow control (Layer 2), in a separate enforcement layer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The check is point-in-time.&lt;/strong&gt; State can change after verification. The harness checks a configured push URL but does not perform or authorize the later &lt;code&gt;git push&lt;/code&gt;. Its Gitleaks check covers the staged diff examined by the scanner, not every file or every secret.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Those limitations are reasons to keep human approval separate from independent enforcement, such as repository-side controls. Human approval is a workflow decision, not independent enforcement; the local harness replaces neither.&lt;/p&gt;

&lt;h2&gt;
  
  
  The useful boundary
&lt;/h2&gt;

&lt;p&gt;The goal is not to prove that an AI assistant is safe. It is narrower: &lt;strong&gt;before a selected Git workflow continues, make certain mismatches observable and stop when required checks cannot be accepted.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The full &lt;a href="https://osiix.com/en/library/ai-git-safety-harness.html" rel="noopener noreferrer"&gt;English design article on OSIIX&lt;/a&gt; explains the checks in detail. For the current implementation—including its separate &lt;code&gt;AllowedStagedFiles&lt;/code&gt; parameter—use the &lt;a href="https://github.com/mars70s/ai-workflow-safety-harness/tree/605f95cc2499120db8557f454312580fab2279a3/harnesses/git" rel="noopener noreferrer"&gt;commit-pinned source&lt;/a&gt;, &lt;a href="https://github.com/mars70s/ai-workflow-safety-harness/blob/605f95cc2499120db8557f454312580fab2279a3/harnesses/git/docs/getting-started.md" rel="noopener noreferrer"&gt;Getting Started guide&lt;/a&gt;, and &lt;a href="https://github.com/mars70s/ai-workflow-safety-harness/blob/605f95cc2499120db8557f454312580fab2279a3/harnesses/git/docs/limitations.md" rel="noopener noreferrer"&gt;limitations&lt;/a&gt;, rather than treating every illustrative snippet in the earlier article as the latest tested code.&lt;/p&gt;

&lt;p&gt;If you use AI-assisted Git automation, which of these checks is enforced &lt;em&gt;outside&lt;/em&gt; the agent-controlled execution path, and which is only a convention the agent is expected to follow?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>git</category>
      <category>automation</category>
    </item>
    <item>
      <title>A Test Passed. But What Did It Actually Test?</title>
      <dc:creator>mars70s</dc:creator>
      <pubDate>Wed, 07 Oct 2026 14:21:08 +0000</pubDate>
      <link>https://dev.to/mars70s/a-test-passed-but-what-did-it-actually-test-i5p</link>
      <guid>https://dev.to/mars70s/a-test-passed-but-what-did-it-actually-test-i5p</guid>
      <description>&lt;p&gt;A test passed. That sounds reassuring.&lt;/p&gt;

&lt;p&gt;But before treating that PASS as evidence, there is a more basic question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What exactly did the test execute?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is surprisingly easy to lose the connection between a test result and the implementation that result is supposed to validate. This became especially visible while reviewing a validation record from my own development work.&lt;/p&gt;

&lt;h2&gt;
  
  
  A PASS is not enough
&lt;/h2&gt;

&lt;p&gt;A test result normally tells us something about a specific target under specific conditions.&lt;/p&gt;

&lt;p&gt;At minimum, I want to know things such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What file or implementation was executed?&lt;/li&gt;
&lt;li&gt;Which version was it?&lt;/li&gt;
&lt;li&gt;Which test script produced the result?&lt;/li&gt;
&lt;li&gt;Under what environment was it executed?&lt;/li&gt;
&lt;li&gt;Can the result still be tied to that same target later?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without that information, a PASS may be real while still being weak evidence for the claim we want to make.&lt;/p&gt;

&lt;p&gt;The problem is not necessarily that the test itself is wrong. The problem may simply be that the evidence does not establish the identity of the thing that passed.&lt;/p&gt;

&lt;h2&gt;
  
  
  I initially made a stronger claim than the evidence supported
&lt;/h2&gt;

&lt;p&gt;While reviewing an earlier validation record, I initially interpreted the evidence as a specific failure mechanism.&lt;/p&gt;

&lt;p&gt;The working explanation was roughly:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;One implementation may have been treated as evidence for another.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That was a coherent explanation, but the surviving evidence did not support it strongly enough.&lt;/p&gt;

&lt;p&gt;When I went back through the retained scripts, outputs, filesystem metadata, and validation records, I could confirm one thing: the record itself did not identify the runner, the implementation, or the invocation path behind its PASS results.&lt;/p&gt;

&lt;p&gt;But I could &lt;strong&gt;not&lt;/strong&gt; reliably reconstruct the stronger causal details.&lt;/p&gt;

&lt;p&gt;For example, the surviving evidence was not enough to establish:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what the intended validation target was,&lt;/li&gt;
&lt;li&gt;whether a retained run script, which executed local functions, was the run that produced the PASS record,&lt;/li&gt;
&lt;li&gt;whether those local functions were intended as a test double,&lt;/li&gt;
&lt;li&gt;how the files involved relate to each other (lineage, copy direction, or creation order),&lt;/li&gt;
&lt;li&gt;or whether AI was involved at all.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those remained unknown.&lt;/p&gt;

&lt;p&gt;So the stronger explanation had to be withdrawn.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the evidence actually supported
&lt;/h2&gt;

&lt;p&gt;The defensible conclusion was narrower:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The verification record did not sufficiently identify its executed validation target to attribute the PASS to a specific implementation from the record alone.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The finding is not:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"The wrong implementation was tested."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The evidence does not support that statement.&lt;/p&gt;

&lt;p&gt;The observable problem was:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"The recorded PASS could not be attributed to a specific implementation from the record alone."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That distinction matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters in AI-assisted workflows
&lt;/h2&gt;

&lt;p&gt;One caveat first: the evidence in this case does not establish whether AI was involved, and a single case says nothing about how often this happens. What follows is a general observation, not a finding from the case.&lt;/p&gt;

&lt;p&gt;AI-assisted development can create many intermediate artifacts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;generated scripts,&lt;/li&gt;
&lt;li&gt;wrappers,&lt;/li&gt;
&lt;li&gt;temporary implementations,&lt;/li&gt;
&lt;li&gt;test helpers,&lt;/li&gt;
&lt;li&gt;copied code,&lt;/li&gt;
&lt;li&gt;diagnostic scripts,&lt;/li&gt;
&lt;li&gt;regenerated files,&lt;/li&gt;
&lt;li&gt;and revised versions of the same component.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of those are inherently bad.&lt;/p&gt;

&lt;p&gt;But they increase the number of objects that can exist between:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;what we intended to validate&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;what was actually executed.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If the validation record only says:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RESULT=PASS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;we know very little.&lt;/p&gt;

&lt;p&gt;Even this is better:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TEST=verify-something.ps1
RESULT=PASS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But it still may not tell us which implementation that test exercised.&lt;/p&gt;

&lt;p&gt;For stronger evidence, the record needs enough identity information to reconstruct the relationship.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TARGET:
  path
  version or commit
  content hash where useful

TEST:
  path
  version or hash

ENVIRONMENT:
  relevant tool versions

RESULT:
  PASS / FAIL

BOUNDARY:
  what this result does and does not establish
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact format is not important. The ability to trace the result back to the tested object is.&lt;/p&gt;

&lt;p&gt;Where hashes are used as evidence, capturing them at the relevant execution or validation boundary is stronger than recomputing them later.&lt;/p&gt;

&lt;h2&gt;
  
  
  PASS should be a bounded statement
&lt;/h2&gt;

&lt;p&gt;I now try to read a PASS as something closer to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Under these conditions, this identified test produced this result against this identified target.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;blockquote&gt;
&lt;p&gt;The implementation is correct.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And definitely not:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The system is safe.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Those are much larger claims.&lt;/p&gt;

&lt;p&gt;A useful validation record therefore contains not only what was observed, but also what remains outside the evidence.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OBSERVED:
- identified test completed successfully
- expected exit code was observed
- target identity was recorded

NOT ESTABLISHED:
- universal compatibility
- production safety
- inability to bypass the control
- correctness outside the tested conditions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This may make the record look less impressive, but it also makes it much harder to accidentally reuse the result as evidence for something it never proved.&lt;/p&gt;

&lt;h2&gt;
  
  
  The uncomfortable part: correcting your own story
&lt;/h2&gt;

&lt;p&gt;The most useful lesson from this case was not technical. It was methodological.&lt;/p&gt;

&lt;p&gt;When investigating a result, it is easy to build a coherent explanation from incomplete evidence. Once that explanation has a name and several paragraphs around it, it becomes surprisingly difficult to abandon.&lt;/p&gt;

&lt;p&gt;But the explanation is not the evidence.&lt;/p&gt;

&lt;p&gt;If later review shows that the evidence only supports a narrower statement, the claim should become narrower too.&lt;/p&gt;

&lt;p&gt;In my case, that meant replacing a satisfying causal story with a much more limited conclusion about target identity.&lt;/p&gt;

&lt;p&gt;That was the right trade.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a later validation record preserves
&lt;/h2&gt;

&lt;p&gt;A later, separate validation record shows what more explicit identity information can look like. The historical case neither confirms nor invalidates that later record.&lt;/p&gt;

&lt;p&gt;For one Git safety harness, the validation record includes items such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;implementation commit,&lt;/li&gt;
&lt;li&gt;source file SHA-256,&lt;/li&gt;
&lt;li&gt;test file SHA-256,&lt;/li&gt;
&lt;li&gt;Git version,&lt;/li&gt;
&lt;li&gt;PowerShell versions,&lt;/li&gt;
&lt;li&gt;Gitleaks version (a secret scanner),&lt;/li&gt;
&lt;li&gt;individual fail-closed and success-path results,&lt;/li&gt;
&lt;li&gt;and an explicit list of what the tests do not prove.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here, fail-closed means stopping when a required check cannot be completed instead of treating an unverifiable state as success.&lt;/p&gt;

&lt;p&gt;This does not make the harness universally correct or secure.&lt;/p&gt;

&lt;p&gt;It does something more modest:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;it makes the validation evidence easier to bind to the object that was actually tested.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A small checklist
&lt;/h2&gt;

&lt;p&gt;Before accepting a PASS as evidence, I now ask:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What exactly was executed?&lt;/li&gt;
&lt;li&gt;Can I identify its version or contents?&lt;/li&gt;
&lt;li&gt;What test produced the result?&lt;/li&gt;
&lt;li&gt;Under what conditions?&lt;/li&gt;
&lt;li&gt;What claim does this result actually support?&lt;/li&gt;
&lt;li&gt;What does it not establish?&lt;/li&gt;
&lt;li&gt;Could I reconstruct that relationship later from the preserved evidence?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If those questions cannot be answered, running more tests may not solve the real problem.&lt;/p&gt;

&lt;p&gt;The missing piece may be the identity of the verification target itself.&lt;/p&gt;




&lt;p&gt;The underlying records for this case are not public, and the review was my own rather than a third-party audit.&lt;/p&gt;

&lt;p&gt;Further reading:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://osiix.com/en/portfolio/evidence/verification-target-identity-gap/" rel="noopener noreferrer"&gt;When a PASS Record Does Not Identify Its Validation Target&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://osiix.com/en/library/ai-git-safety-harness.html" rel="noopener noreferrer"&gt;Safety Harness for AI-Assisted Git Operations&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>testing</category>
      <category>devops</category>
    </item>
    <item>
      <title>"10 hours" and "around two weeks" are not the same kind of number</title>
      <dc:creator>mars70s</dc:creator>
      <pubDate>Sun, 20 Sep 2026 16:44:27 +0000</pubDate>
      <link>https://dev.to/mars70s/10-hours-and-around-two-weeks-are-not-the-same-kind-of-number-5123</link>
      <guid>https://dev.to/mars70s/10-hours-and-around-two-weeks-are-not-the-same-kind-of-number-5123</guid>
      <description>&lt;p&gt;In September 2026, Palo Alto Networks Unit 42 published a case involving&lt;br&gt;
an AI-assisted intrusion into an enterprise network. The article includes&lt;br&gt;
figures like "less than 10 hours," "more than 50 MITRE ATT&amp;amp;CK techniques,"&lt;br&gt;
and "around two weeks" for what a human operator would normally need.&lt;/p&gt;

&lt;p&gt;It's tempting to divide those numbers and conclude "AI made this 30x faster."&lt;br&gt;
I don't think the source material supports that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two different kinds of numbers
&lt;/h2&gt;

&lt;p&gt;"Less than 10 hours" is a reported duration of activity.&lt;/p&gt;

&lt;p&gt;"Around two weeks" is Unit 42's comparative assessment of what a human&lt;br&gt;
operator would typically require for impact of that scale.&lt;/p&gt;

&lt;p&gt;The public article doesn't include a same-conditions human-only comparison,&lt;br&gt;
team size, skill composition, tools used, or a detailed calculation method.&lt;br&gt;
So "AI turned two weeks into 10 hours" isn't a measured speedup ratio —&lt;br&gt;
it's two different types of numbers sitting next to each other.&lt;/p&gt;

&lt;h2&gt;
  
  
  The article changed after publication
&lt;/h2&gt;

&lt;p&gt;I checked the Wayback Machine capture from the publication date against&lt;br&gt;
the current version. Two things changed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"as part of a ransomware attack" → "as part of a ransom attack"
(the page's own update history later clarifies this was an intrusion,
not a ransomware attack)&lt;/li&gt;
&lt;li&gt;"public API endpoint" → "publicly accessible web service"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The second change isn't explained in the page's own changelog. I can't&lt;br&gt;
establish when it happened or why — so I don't speculate. I just note&lt;br&gt;
that the wording changed.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's actually confirmed about AI use
&lt;/h2&gt;

&lt;p&gt;Two separate evidence paths exist:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The threat actor's own account (told to Unit 42 during negotiations)
that they used frontier AI models and attack-specific agentic frameworks&lt;/li&gt;
&lt;li&gt;Technical indicators Unit 42 observed independently — parallel LLM
calls, structured Markdown passed between agents, custom scripts&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Both matter. Neither, alone or together, establishes that AI autonomously&lt;br&gt;
ran every stage of the intrusion. Unit 42's own Figure 1 shows a human&lt;br&gt;
actor setting objectives and making key decisions while agents execute —&lt;br&gt;
closer to human-directed / agent-executed than fully autonomous.&lt;/p&gt;

&lt;h2&gt;
  
  
  A hypothesis worth testing: parallelization, not just speed
&lt;/h2&gt;

&lt;p&gt;Here's where I'll go beyond what Unit 42 states. The public material&lt;br&gt;
can't tell us how many times faster any single task became. But it does&lt;br&gt;
describe multiple agents, parallel LLM calls, and state handed off across&lt;br&gt;
sessions — which suggests a different question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Maybe the effect of AI-assisted intrusion isn't mainly per-task speedup.&lt;br&gt;
Maybe it's lower coordination cost and handoff latency when running&lt;br&gt;
multiple workstreams in parallel.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If that's right, the interesting metrics aren't total elapsed time —&lt;br&gt;
they're things like: how many agents/sessions ran concurrently, how much&lt;br&gt;
independent tasks overlapped in time, how long from observation to next&lt;br&gt;
action, what share of time went to human-approval waits.&lt;/p&gt;

&lt;p&gt;This hypothesis also has a clear failure mode: if a detailed timeline&lt;br&gt;
showed activity was mostly sequential, with few concurrent agents and&lt;br&gt;
long approval waits, the parallelization story falls apart.&lt;/p&gt;

&lt;h2&gt;
  
  
  Full writeup
&lt;/h2&gt;

&lt;p&gt;I go through the source comparison, the evidence paths, and the&lt;br&gt;
full list of what remains unknown in more detail here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://osiix.com/en/library/unit42-ai-assisted-intrusion.html" rel="noopener noreferrer"&gt;https://osiix.com/en/library/unit42-ai-assisted-intrusion.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This article independently reviews public material and does not&lt;br&gt;
indicate any approval, supervision, or affiliation by Palo Alto&lt;br&gt;
Networks or Unit 42.&lt;/p&gt;

</description>
      <category>security</category>
      <category>ai</category>
      <category>llm</category>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>Restorable Backup Safe Cyber Recovery</title>
      <dc:creator>mars70s</dc:creator>
      <pubDate>Sat, 19 Sep 2026 13:58:41 +0000</pubDate>
      <link>https://dev.to/mars70s/restorable-backup-safe-cyber-recovery-3g83</link>
      <guid>https://dev.to/mars70s/restorable-backup-safe-cyber-recovery-3g83</guid>
      <description>&lt;p&gt;You have multiple generations of backups. The newest one restores fine.&lt;br&gt;
Ransomware was detected today. But you don't actually know when the&lt;br&gt;
intrusion started.&lt;/p&gt;

&lt;p&gt;The natural instinct: restore the latest backup. But "restorable" and&lt;br&gt;
"safe to adopt as your recovery point" are not the same claim.&lt;/p&gt;

&lt;p&gt;This is one chapter from a self-study book I've been writing on Backup /&lt;br&gt;
Recovery / Archive design. Here's the short version.&lt;/p&gt;

&lt;h2&gt;
  
  
  Latest ≠ Correct
&lt;/h2&gt;

&lt;p&gt;A backup taken &lt;em&gt;after&lt;/em&gt; compromise may already contain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;encrypted data&lt;/li&gt;
&lt;li&gt;corrupted state&lt;/li&gt;
&lt;li&gt;some other form of unsafe state&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This doesn't mean "newer is dangerous." It means newness alone doesn't&lt;br&gt;
prove correctness.&lt;/p&gt;

&lt;h2&gt;
  
  
  False signals of "clean"
&lt;/h2&gt;

&lt;p&gt;The chapter lists reasons people wrongly declare a backup safe — none of&lt;br&gt;
which, alone, proves it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it restored successfully&lt;/li&gt;
&lt;li&gt;it was protected as immutable&lt;/li&gt;
&lt;li&gt;the hash matched&lt;/li&gt;
&lt;li&gt;antivirus scan passed&lt;/li&gt;
&lt;li&gt;it predates the detection time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each is a useful signal. None is proof on its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two checkpoints, not one
&lt;/h2&gt;

&lt;p&gt;NIST's guidance on cyber recovery separates verification into two stages:&lt;br&gt;
checking the recovery asset &lt;em&gt;before&lt;/em&gt; you use it, and checking the restored&lt;br&gt;
system &lt;em&gt;before&lt;/em&gt; you put it back into production. One check is not enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  The discipline that matters most
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;"Don't turn 'unknown' into 'safe.'"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When the intrusion start time is uncertain — which it often is — that&lt;br&gt;
uncertainty doesn't disappear just because you'd like to move forward.&lt;br&gt;
The chapter treats "we don't know" as an honest state, not a failure to&lt;br&gt;
be papered over.&lt;/p&gt;




&lt;p&gt;Full chapter: &lt;a href="https://osiix.com/en/library/backup-recovery-archive-fundamentals/chapter-11.html" rel="noopener noreferrer"&gt;https://osiix.com/en/library/backup-recovery-archive-fundamentals/chapter-11.html&lt;/a&gt;&lt;br&gt;
Book index: &lt;a href="https://osiix.com/en/library/backup-recovery-archive-fundamentals/" rel="noopener noreferrer"&gt;https://osiix.com/en/library/backup-recovery-archive-fundamentals/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>backup</category>
      <category>disasterrecovery</category>
      <category>security</category>
    </item>
  </channel>
</rss>
