<?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: Jeremy Longshore</title>
    <description>The latest articles on DEV Community by Jeremy Longshore (@jeremy_longshore).</description>
    <link>https://dev.to/jeremy_longshore</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%2F3842419%2Ff5d02b54-daf0-4520-9aef-118fbd0c24ac.jpeg</url>
      <title>DEV Community: Jeremy Longshore</title>
      <link>https://dev.to/jeremy_longshore</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jeremy_longshore"/>
    <language>en</language>
    <item>
      <title>Verify Audit Evidence with a Signed Payload, Not by Format</title>
      <dc:creator>Jeremy Longshore</dc:creator>
      <pubDate>Wed, 14 Oct 2026 11:30:11 +0000</pubDate>
      <link>https://dev.to/jeremy_longshore/verify-audit-evidence-with-a-signed-payload-not-by-format-kjh</link>
      <guid>https://dev.to/jeremy_longshore/verify-audit-evidence-with-a-signed-payload-not-by-format-kjh</guid>
      <description>&lt;p&gt;When many audit-evidence publishers (the systems that produce signed rows of evidence) each emit a different shape and the consumer checks signatures case by case, a tampered row is indistinguishable from a legitimate format change. The consumer has no place to anchor "last good state," so any verification failure either erases history or silently keeps going.&lt;/p&gt;

&lt;p&gt;A reader running an audit trail or evidence pipeline across multiple publishers and one consumer can adopt a different shape this week. One canonical signed statement payload (a fixed envelope of kernel version plus payload plus signature that every publisher fills in identically), one verifier that checks by signature, a preserved snapshot on every rejection. That is what cut this pipeline's tampering failures from "ambiguous" to "rejected with history preserved."&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you verify audit evidence from multiple publishers?
&lt;/h2&gt;

&lt;p&gt;Adopt one canonical signed statement payload: a fixed envelope of kernel version plus payload plus signature that every publisher fills in identically. One verifier parses the envelope, recomputes the digest over the canonical predicate bytes, and checks the signature against the public key named in the envelope. Format evolution shows up as a signature failure; tampering shows up as a signature failure; the two are no longer distinguishable to a silent verifier. A preserved last-verified snapshot rides with every rejection so the dashboard can answer what the system believed yesterday without needing yesterday's process to be alive.&lt;/p&gt;

&lt;h2&gt;
  
  
  The format-evolution trap
&lt;/h2&gt;

&lt;p&gt;The natural reflex is to keep adapting the verifier. Each publisher says its evidence grew up: a new field, a renamed key, a moved nested block. The verifier grows a new branch for each, and the test matrix grows with it. The signed-payload approach is to stop growing the verifier at all and stop asking the verifier to know any individual publisher's shape. The signature binds to the digest of the full payload bytes; the verifier either trusts that digest matches the signed payload or it does not.&lt;/p&gt;

&lt;p&gt;What makes this load bearing is that the failure mode is silent. A coerced signature over a slightly different payload passes a content check and fails a signature check. Both look like progress on a glance: the row got bigger, a field appeared, the count went up. The dashboard in this case was logging "verified" against a local witness and "rejected" against the kernel-signed digest, and the two tables had been drifting apart for three nights before anyone noticed.&lt;/p&gt;

&lt;p&gt;The audit-harness (the in-repo package of deterministic test-quality checks) release carried a verified registry signature and provenance attestation on 2026-10-12, and that is what made the change carry weight. The pipeline was not adopting a new idea; it was adopting a long-standing in-toto-style attestation pattern that the harness had already shipped.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one canonical statement payload
&lt;/h2&gt;

&lt;p&gt;Every publisher now emits the same shape: a kernel-versioned envelope with a typed statement, a predicate payload under it, a digest over the canonical predicate bytes, and a signature bound to that digest. The kernel version is part of the bytes that get signed, so a version bump cannot pass as the same payload. The payload bytes follow; the digest covers them; the signature covers the envelope plus the digest.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;statement:
  kernel: "audit-payload/v1"
  subject:
    - name: "publisher-name"
      digest: { sha256: "&amp;lt;hex&amp;gt;" }
  predicate:
    type: "https://intent-eval-platform.io/predicate/&amp;lt;kind&amp;gt;"
    payload:
      &amp;lt;canonical JSON: keys sorted, no whitespace, RFC 8785&amp;gt;
  metadata:
    build_at: "2026-10-12T13:45:00Z"
    source: "&amp;lt;publisher repo&amp;gt;"
envelope:
  digest: { sha256: "&amp;lt;hex of canonical predicate bytes&amp;gt;" }
  signature:
    pub_key_id: "&amp;lt;fingerprint&amp;gt;"
    value: "&amp;lt;base64&amp;gt;"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The kernel is the only component the verifier needs to know. Below the kernel, payloads are opaque to the verifier; their shape belongs to the publisher that emits them. Above the kernel, signatures travel with rows. The witness table only needs three columns: &lt;code&gt;subject&lt;/code&gt;, &lt;code&gt;digest&lt;/code&gt;, &lt;code&gt;signature&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is the reverse of how multi-publisher audits usually grow. The usual pressure is "the consumer has to understand the publisher," which pushes every format decision into the consumer. Inverting that pressure means every format decision lives with the publisher; the consumer only verifies that the signature covers the kernel and the digest.&lt;/p&gt;

&lt;h2&gt;
  
  
  One consumer, verification by signature
&lt;/h2&gt;

&lt;p&gt;The dashboard verifier does three things in order, and only those three. It parses the envelope, recomputes the digest over the canonical predicate bytes, and checks the signature against the public key named in the envelope. A rejection at any step moves the row into a holding area; a pass moves it into the witness table under the subject digest.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;envelope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;keyring&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Keyring&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;kernel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;envelope&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;statement&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kernel&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;kernel&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;SUPPORTED_KERNEL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kernel_unsupported&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;kernel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;predicate_bytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;canonicalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;envelope&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;statement&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;predicate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;predicate_bytes&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;hexdigest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;declared&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;envelope&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;envelope&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;digest&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sha256&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;declared&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;digest_mismatch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;declared&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;declared&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;recomputed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="n"&gt;pub&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keyring&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;envelope&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;envelope&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;signature&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pub_key_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;pub&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unknown_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;...)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;pub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;predicate_bytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;envelope&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;envelope&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;signature&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bad_signature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;envelope&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;statement&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;subject&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                          &lt;span class="n"&gt;digest&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                          &lt;span class="n"&gt;signature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;envelope&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;envelope&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;signature&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The verifier does not branch on predicate type, publisher, or layout. If a publisher adds a field, the canonicalizer's output changes, the digest changes, and the signature has to follow or verification fails. Format evolution shows up as a signature failure; that is the design, not a defect.&lt;/p&gt;

&lt;h2&gt;
  
  
  When verification fails, hold the last good snapshot
&lt;/h2&gt;

&lt;p&gt;A rejection is supposed to be an event the system keeps, not one it papers over. The tamper-evident holding area preserves the rejected envelope verbatim; the witness table keeps the last accepted row for that subject. A mutation that does not pass is a mutation the consumer has not yet agreed on, and the right answer is to surface that without erasing what already passed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;verdict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Snapshot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ApplyResult&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reject&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rejections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;envelope&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;envelope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reason&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;received_at&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;utcnow&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rejections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prune&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keep_last&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;REJECTION_WINDOW&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ApplyResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;held&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;last_known&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;witnesses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;rejection&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;witnesses&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;digest&lt;/span&gt;
    &lt;span class="n"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;persist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ApplyResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;accepted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;digest&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The snapshot sits alongside the witness table for the same reason the witness table is keyed by subject digest. The dashboard can answer "what did the system believe yesterday?" without needing yesterday's process to be alive. That is the property that broke before, when a forced schema migration overwrote the witness table with a partially-verified copy.&lt;/p&gt;

&lt;h2&gt;
  
  
  What got shipped
&lt;/h2&gt;

&lt;p&gt;Six rejections in cross-repository tests covered the cases the old verifier could not tell apart: a single-byte payload mutation, a canonicalization difference on whitespace, a key id not in the ring, a signature over a tampered digest, a kernel version one off, and a payload reordered against an older row. Each rejection kept the witness for its subject. None of them caused history loss.&lt;/p&gt;

&lt;p&gt;J-Rig (an internal governed evidence publisher) emitted fourteen canonical rows from the merged commit on the night of 2026-10-12. All fourteen verify against the dashboard signature path on the same day. J-Rig's twenty-four payload contracts pass across kernel versions 0.10.0 and 0.11.0; a stricter type check is now in CI for the test-only mismatch between the branded types in those versions.&lt;/p&gt;

&lt;p&gt;A second finding came out of the same session: the trace-intelligence program's dependency graph needed 438 edges added to align final review and production-adoption with their prerequisites. The graph was repaired without changing ownership, acceptance criteria, or completion states. The collision between the two is the one to surface: a missing migration record and a missing dependency edge are both evidence the system was lying to itself about state; the same cross-repo fix path surfaced both, and neither was visible from the dashboard before it landed.&lt;/p&gt;

&lt;p&gt;A real failure worth keeping. The scanner adapter had been treating gitleaks's exit-1 as a policy finding, conflating scanner crashes with findings. A contract-test surface reproduces this now, and required-missing-tool behavior stays advisory instead of silently raising real findings. The adapter is no longer a place where the verifier has to second-guess the publisher's report.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not the obvious approach?
&lt;/h2&gt;

&lt;p&gt;Two alternatives were on the table. The first was a richer schema with publisher-specific extensions and a per-publisher verifier; the second was a content-addressed store that names files by their hash and trusts whoever can read them.&lt;/p&gt;

&lt;p&gt;The richer schema pushes the format-decision pressure the wrong way. Every new field forces the consumer to learn a shape it does not own, and a tampered field reads as a new field until someone diffs the schema. The cross-repository tests in this pipeline had eight publisher schemas to maintain, and three of them were already a quarter behind. A per-publisher verifier is the natural extension of that path; it does not survive the next publisher.&lt;/p&gt;

&lt;p&gt;The content-addressed store is closer to the working shape, but it answers the wrong question. A digest proves the bytes are intact; it does not prove the publisher had the right to issue them. A row whose digest matches but whose signing key is not in the ring still passes. The signed envelope binds the digest to a key id, and the verifier's second step is the only place that check lives.&lt;/p&gt;

&lt;p&gt;A real reversal surfaced in the J-Rig kernel compatibility work. The earlier verifier accepted a "legacy fallback" branch so older J-Rig rows would not be lost on the cutover; that branch was a place a tampered payload could land without the witness table noticing. Removing the fallback is what makes the dashboard reject every J-Rig row that comes through the tampering or fallback branch today; the fourteen nightly rows verify on the canonical path. Keeping the old rows was the wrong kind of compatibility. The right kind is keeping the witness for the same subject, not the same shape.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use this
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Pick one canonical signed payload shape for every publisher in the pipeline. Kernel version plus payload digest plus signature. Anything below the kernel is the publisher's choice; anything above is the signature's. Format evolution shows up as a signature failure, not as a silent accept.&lt;/li&gt;
&lt;li&gt;Move verification out of every publisher-specific verifier. One consumer, one supported kernel, one signature check. Rejections are a feature. Cross-repo tests should treat new publishers as an unknown key id, not as a new branch.&lt;/li&gt;
&lt;li&gt;Preserve the last good witness for every subject on every rejection. The dashboard answers "what did we believe yesterday?" by reading the witness table, which means the witness table has to survive the rejection that pointed at a tampered payload.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The full migration is live on &lt;a href="https://intent-eval-platform.io" rel="noopener noreferrer"&gt;intent-eval-platform.io&lt;/a&gt;: eight publishers, one verifier, the J-Rig nightly run, and audit-harness 1.5.1 on the registry with verified provenance.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How do you verify audit evidence from multiple publishers?
&lt;/h3&gt;

&lt;p&gt;Adopt one canonical signed statement payload: a fixed envelope of kernel version plus payload plus signature that every publisher fills in identically. One verifier parses the envelope, recomputes the digest over the canonical predicate bytes, and checks the signature against the public key named in the envelope. Format evolution shows up as a signature failure; tampering shows up as a signature failure; the two are no longer distinguishable to a silent verifier.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a signed statement payload in an audit pipeline?
&lt;/h3&gt;

&lt;p&gt;A fixed envelope containing a typed statement, a payload digest, and a signature bound to that digest. Every publisher fills in the same envelope; payloads below the kernel can be any shape the publisher chooses. The signature covers the digest plus the envelope, so a single-byte payload mutation or a canonicalization difference on whitespace fails the check while legitimate history still verifies.&lt;/p&gt;

&lt;h3&gt;
  
  
  What should a verifier do when an audit row fails verification?
&lt;/h3&gt;

&lt;p&gt;Move the rejected envelope verbatim into a holding area; keep the last accepted row for that subject in the witness table; persist the last-known-good snapshot so the dashboard can answer what the system believed yesterday without needing yesterday's process to be alive. A rejection is an event the system keeps, not one it papers over.&lt;/p&gt;

&lt;p&gt;{&lt;br&gt;
  "&lt;a class="mentioned-user" href="https://dev.to/context"&gt;@context&lt;/a&gt;": "&lt;a href="https://schema.org" rel="noopener noreferrer"&gt;https://schema.org&lt;/a&gt;",&lt;br&gt;
  "@type": "FAQPage",&lt;br&gt;
  "mainEntity": [&lt;br&gt;
    {&lt;br&gt;
      "@type": "Question",&lt;br&gt;
      "name": "How do you verify audit evidence from multiple publishers?",&lt;br&gt;
      "acceptedAnswer": {&lt;br&gt;
        "@type": "Answer",&lt;br&gt;
        "text": "Adopt one canonical signed statement payload: a fixed envelope of kernel version plus payload plus signature that every publisher fills in identically. One verifier parses the envelope, recomputes the digest over the canonical predicate bytes, and checks the signature against the public key named in the envelope. Format evolution shows up as a signature failure; tampering shows up as a signature failure; the two are no longer distinguishable to a silent verifier."&lt;br&gt;
      }&lt;br&gt;
    },&lt;br&gt;
    {&lt;br&gt;
      "@type": "Question",&lt;br&gt;
      "name": "What is a signed statement payload in an audit pipeline?",&lt;br&gt;
      "acceptedAnswer": {&lt;br&gt;
        "@type": "Answer",&lt;br&gt;
        "text": "A fixed envelope containing a typed statement, a payload digest, and a signature bound to that digest. Every publisher fills in the same envelope; payloads below the kernel can be any shape the publisher chooses. The signature covers the digest plus the envelope, so a single-byte payload mutation or a canonicalization difference on whitespace fails the check while legitimate history still verifies."&lt;br&gt;
      }&lt;br&gt;
    },&lt;br&gt;
    {&lt;br&gt;
      "@type": "Question",&lt;br&gt;
      "name": "What should a verifier do when an audit row fails verification?",&lt;br&gt;
      "acceptedAnswer": {&lt;br&gt;
        "@type": "Answer",&lt;br&gt;
        "text": "Move the rejected envelope verbatim into a holding area; keep the last accepted row for that subject in the witness table; persist the last-known-good snapshot so the dashboard can answer what the system believed yesterday without needing yesterday's process to be alive. A rejection is an event the system keeps, not one it papers over."&lt;br&gt;
      }&lt;br&gt;
    }&lt;br&gt;
  ]&lt;br&gt;
}&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Posts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="//{{&lt;%20ref%20"&gt;}}"&amp;gt;Name the Single Authority in a Daily Pipeline&lt;/a&gt; - Why one named owner per concern beats committee routing in a daily pipeline&lt;/li&gt;
&lt;li&gt;
&lt;a href="//{{&lt;%20ref%20"&gt;}}"&amp;gt;Three-Pass Settlement for a Recurring AI Pipeline Contract&lt;/a&gt; - How three passes (producer, settlement, audit) settle a recurring AI pipeline contract&lt;/li&gt;
&lt;li&gt;
&lt;a href="//{{&lt;%20ref%20"&gt;}}"&amp;gt;Exit Zero Is Not Push OK&lt;/a&gt; - A cron that reports OK after a failed git rebase is a load-bearing lie&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>audit</category>
      <category>evidence</category>
      <category>supplychain</category>
      <category>signedpayload</category>
    </item>
    <item>
      <title>Park a Migration Without Losing the Work</title>
      <dc:creator>Jeremy Longshore</dc:creator>
      <pubDate>Sat, 10 Oct 2026 11:30:13 +0000</pubDate>
      <link>https://dev.to/jeremy_longshore/park-a-migration-without-losing-the-work-5443</link>
      <guid>https://dev.to/jeremy_longshore/park-a-migration-without-losing-the-work-5443</guid>
      <description>&lt;p&gt;A migration that ships by reaching the default branch with a green badge still has a second decision hidden inside it: do we point production at it today, in a week, or ever. When the build and the deploy are welded together, that second decision leaks into rollback theater even when the right answer is to wait months. The pattern this post calls publish-and-park splits them on purpose, so parking an owner can be the cutover's moment instead of its point of no return.&lt;/p&gt;

&lt;p&gt;A Flask-to-Django refactor in &lt;code&gt;catalyst-onboarding&lt;/code&gt; (a public onboarding repo) reached that fork in October. The Django stack was complete, gated, and pushed to two feature branches as atomic fast-forwards. Production stayed on Flask. The work stayed on the feature branches where it had landed. The pattern that made the cutover reversible is what this post is about.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the publish-and-park pattern for software migrations?
&lt;/h2&gt;

&lt;p&gt;The publish-and-park pattern splits a refactor's build from its cutover so parking the work is reversible. The gate suite runs on the merged commit on a feature branch with no production mutation, and a dated "do not cut over" record lands in the repo. Production stays on the old stack until a separate decision points it at the new one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pattern, in one sentence
&lt;/h2&gt;

&lt;p&gt;Push the refactor to its feature branches as an atomic fast-forward, run the full gate suite on the merged commit, ship nothing to production, write the explicit "do not cut over" record, and open a successor planning repo so the parked work has somewhere forward to go.&lt;/p&gt;

&lt;p&gt;Five invariants make a parked refactor recoverable instead of abandoned:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Atomic push to a feature branch.&lt;/strong&gt; The work lands as one fast-forward commit. No merge commit. No force push. The branch tip is byte-identical to the merged result.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Full gate suite on the merged commit.&lt;/strong&gt; Unit, integration, contract, coverage audit, security, and an independent reviewer all run against the tip. Green badge is recorded on the commit, not on a moving branch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No production mutation at ship time.&lt;/strong&gt; The cutover is a separate operation, owned by a separate decision, executed on a separate day.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An explicit "do not cut over" document.&lt;/strong&gt; A dated decision record lives at the top of the repo. Future readers find it before they touch the parked work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A successor repo.&lt;/strong&gt; The parked work has somewhere forward to go. It is not a dead branch waiting for a code archaeologist.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When all five hold, parking an owner is reversible. When any one is missing, parking an owner is abandonment in slow motion.&lt;/p&gt;

&lt;h2&gt;
  
  
  The build-up trail
&lt;/h2&gt;

&lt;p&gt;The Flask to Django migration was not a weekend. It was six stacked PRs landed over a single day, each one a thin slice of the new lifecycle. The numbering gap between #113 and #115 is an unrelated CI-infra fix that interleaved between the intake and review slices; it is not part of the migration stack and it would be a mistake to read the migration as seven PRs because of it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PR #113 feat(intake):     add native Django intake and durable Temporal mail
PR #115 feat(review):     run native stages with durable evidence and bounded admission
PR #116 feat(deploy):     promote authenticated immutable image archives
PR #117 feat(profile):    persist native review profiles and durable CRM projection
PR #118 feat(ci):         record complete shard phase and worker timings
PR #119 feat(onboarding): add Select partner footers and repair bounded CI setup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each PR carried its own gate subset. The full suite ran only when the last commit on the immutable milestone branch was in place. That ordering matters: a partial green badge on a partial stack is not a parking artifact. It is a half-truth.&lt;/p&gt;

&lt;h2&gt;
  
  
  The atomic push
&lt;/h2&gt;

&lt;p&gt;The push that turned the work into a parking artifact looked like this:&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;# After the full makecheck suite passed locally and was re-run by CI on the same SHA:&lt;/span&gt;
git push origin feat/django-agreement-lifecycle:feat/django-agreement-lifecycle &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--ff-only&lt;/span&gt;
git push origin feat/django-agreement-notifications:feat/django-agreement-notifications &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--ff-only&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two pushes, both fast-forward only. The remote tip is byte-identical to the local tip. No merge commit hides what was actually shipped. No force push re-writes history. A reader six months from now can run &lt;code&gt;git log&lt;/code&gt; on either branch and reconstruct the exact build state.&lt;/p&gt;

&lt;p&gt;The atomic property is the load-bearing one. A merge commit would let a future force-push hide reverts. A non-fast-forward push would break anyone who already has the branch checked out. Neither breaks the next person, but both break the parking pattern's audit trail.&lt;/p&gt;

&lt;h2&gt;
  
  
  The gate suite on the merged commit
&lt;/h2&gt;

&lt;p&gt;The full gate suite ran on the immutable milestone commit, not on the moving feature branches:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;makecheck terminal PASS 598.411s
  1746 unit + 1 skip
  2764 SQLite + 160 skip
  436 pilot
  static + security

PG terminal 4659 PASS / 14 skip / 4673 collected
  1262.33s test / 1271.060s whole

v2 coverage audit PASS
Independent reviewer APPROVE &amp;lt;commit&amp;gt; ONLY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reviewer line is the one most teams skip. A human (or a strictly scoped reviewer agent) confirms the gate results match the code. Without that confirmation, a green badge is a CI vendor's promise. With it, a green badge is a recorded decision by the team that owns the codebase. The parked refactor is recoverable because the gate results are pinned to the commit, not to the workflow run.&lt;/p&gt;

&lt;h2&gt;
  
  
  The cutover stays on Flask
&lt;/h2&gt;

&lt;p&gt;Production stayed on Flask main. The Django stack was pushed to its feature branches, and the PR was converted to draft. A full-ref backup bundle was written to &lt;code&gt;~/backups/catalyst-onboarding-preserve-*&lt;/code&gt; the following morning; the path-embedded date is for the snapshot job that wrote it, not for the work itself. The bundle is belt-and-suspenders: the feature branches are the primary artifact, the backup is the secondary. Neither mutates production.&lt;/p&gt;

&lt;p&gt;This is the second decision, the one the publish-and-park pattern splits out. The decision is not "is the work done." It is "is this the right moment to point production at it." The two questions have different owners, different evidence, and different reversibility costs. Welding them together is what makes migrations feel like a one-way door.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not the obvious approach?
&lt;/h2&gt;

&lt;p&gt;The obvious approach is to merge the Django stack to &lt;code&gt;main&lt;/code&gt;, let CI go green, and cut over. Three reasons that fails:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The badge is on the branch, not the commit.&lt;/strong&gt; A green badge on &lt;code&gt;main&lt;/code&gt; after the merge tells you the gate suite passed against a moving target. Anyone who has reset &lt;code&gt;main&lt;/code&gt; to undo the merge invalidates the badge retroactively. The parked refactor has no such exposure: the gate results are pinned to the commit SHA on the feature branch, and that SHA does not move.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cutting over is a single failure domain.&lt;/strong&gt; If the cutover breaks, you do not know whether the bug is in the new code, in the deploy step, or in the rollback. With the cutover decoupled, the new code can sit on a feature branch for months while the deploy step is rehearsed separately. The two failure domains stay separate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The "do not cut over" decision has nowhere to live.&lt;/strong&gt; A merge to &lt;code&gt;main&lt;/code&gt; is the act of cutting over, by definition. There is no document you can write that says "this is on &lt;code&gt;main&lt;/code&gt; but do not use it" without breaking the social contract that &lt;code&gt;main&lt;/code&gt; is production. The decision record has to land before the merge, which means the merge has to be deferred, which means the work has to live on a feature branch.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The pattern is not a workaround for a missing feature. It is the only shape that makes parking an owner recoverable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The "do not cut over" record
&lt;/h2&gt;

&lt;p&gt;The decision record is a PR, not a wiki page and not a numbered-record entry. PR #124 in &lt;code&gt;catalyst-onboarding&lt;/code&gt; carries the dated decision that the Django stack stays parked and Flask stays in production. The PR body names the commit, links the full-ref bundle, lists the gates that passed, and names the successor repo.&lt;/p&gt;

&lt;p&gt;The PR is the artifact a future reader finds before they touch the parked work. A wiki page rots. A numbered-record entry (each repo's dated folder of decision history) can be moved, renamed, or lost when the numbering scheme changes. A PR lives at the top of the repo's pull request list until it is closed, and its merge commit lives in &lt;code&gt;main&lt;/code&gt; history forever.&lt;/p&gt;

&lt;h2&gt;
  
  
  The successor repo
&lt;/h2&gt;

&lt;p&gt;The parked refactor is not abandoned because it has a successor: &lt;code&gt;intent-solutions-io/catalyst-onboarding-v2&lt;/code&gt;, opened the following morning with the beads (a tracked task record in the repo's issue database) prefix &lt;code&gt;catalyst-v2&lt;/code&gt; and no code. The planning-phase foundation exists so the parked work has somewhere forward to go.&lt;/p&gt;

&lt;p&gt;A parked refactor without a successor is a dead branch. A parked refactor with a successor is a deferred plan. The successor repo does not have to contain the parked work; it has to contain the plan for the parked work. The Django stack on &lt;code&gt;feat/django-agreement-lifecycle&lt;/code&gt; is the parking artifact; &lt;code&gt;catalyst-onboarding-v2&lt;/code&gt; is the forward home.&lt;/p&gt;

&lt;h2&gt;
  
  
  What survives a routine branch cleanup
&lt;/h2&gt;

&lt;p&gt;The parked refactor survived a repo sweep that removed 34 temporary worktrees and deleted 25 merged branches. The work lives on the published feature branches and on &lt;code&gt;main&lt;/code&gt; history, not in disposable worktrees or speculative branches.&lt;/p&gt;

&lt;p&gt;Atomic fast-forward pushes land on real branches with real tips. A repo sweep that removes temporary worktrees and merged branches cannot touch those tips without changing the published history. That is a consequence of invariant one: durable artifacts outlive routine cleanup.&lt;/p&gt;

&lt;h2&gt;
  
  
  What did not change the parked work
&lt;/h2&gt;

&lt;p&gt;In the 24 hours after the parking decision, a parallel hardening window merged fifteen fixes in &lt;code&gt;claude-code-plugins&lt;/code&gt;: patched advisories in shipped MCP servers, upgraded &lt;code&gt;actions/cache&lt;/code&gt;, &lt;code&gt;actions/github-script&lt;/code&gt;, &lt;code&gt;codecov-action&lt;/code&gt;, the cosign installer, &lt;code&gt;download-artifact&lt;/code&gt;, &lt;code&gt;pnpm/action-setup&lt;/code&gt;, and Vitest. None of those PRs touched the parked Django work. None of them needed to. The decoupling held under a load that would have broken a single-stack deployment.&lt;/p&gt;

&lt;p&gt;The point is not that the hardening window was easy. The point is that it was possible without a deploy coordination meeting. Two repos, two lifecycles, no shared cutover.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use this
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Push the refactor as &lt;code&gt;--ff-only&lt;/code&gt; to a feature branch, not as a merge to &lt;code&gt;main&lt;/code&gt;.&lt;/strong&gt; The atomic property is what makes the gate suite pin to a commit instead of a moving branch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run the full gate suite on the merged commit, including the independent reviewer.&lt;/strong&gt; A CI badge is the vendor's promise; a reviewer-approved badge is the team's promise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write the "do not cut over" decision as a PR, and open a successor planning repo.&lt;/strong&gt; The decision has to live where the next reader will find it, and the parked work has to have somewhere forward to go.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Django stack in &lt;code&gt;catalyst-onboarding&lt;/code&gt; is parked. The work is not abandoned. The five invariants held, and parking the cutover became a reversible decision instead of a one-way door.&lt;/p&gt;

&lt;p&gt;The parked Django work and the dated parking decision: &lt;a href="https://github.com/intent-solutions-io/catalyst-onboarding/pull/120" rel="noopener noreferrer"&gt;intentsolutions pull 120&lt;/a&gt; and &lt;a href="https://github.com/intent-solutions-io/catalyst-onboarding/pull/124" rel="noopener noreferrer"&gt;pull 124&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How do you park a refactor without abandoning it?
&lt;/h3&gt;

&lt;p&gt;Five invariants hold: the work lands as an atomic fast-forward push, the gate suite pins to the merged commit (including an independent reviewer), no production mutation happens at ship time, a "do not cut over" decision record lands in the repo, and a successor repo gives the parked work somewhere forward to go. Drop any one and the parked work becomes abandoned in slow motion.&lt;/p&gt;

&lt;h3&gt;
  
  
  When should you delay a production cutover after a green merge?
&lt;/h3&gt;

&lt;p&gt;Delay when a green badge sits on a moving branch, when the cutover and rollback share one failure domain, or when the "do not cut over" decision has nowhere to live. Parking keeps the new code on a feature branch with a pinned badge, so the deploy step can be rehearsed independently before the swap.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why not merge to main and cut over later?
&lt;/h3&gt;

&lt;p&gt;A green badge on main sits on a moving target that any reset invalidates retroactively, a cutover welded to a merge is one failure domain, and a "do not cut over" decision has no place to live when main is the act of cutting over. Parking keeps work, gate results, and decision on separate durable artifacts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Posts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://startaitools.com/posts/three-pass-settlement-recurring-ai-pipeline-contract/" rel="noopener noreferrer"&gt;three-pass-settlement-recurring-ai-pipeline-contract&lt;/a&gt;: A recurring AI pipeline contract project settles only after a third evidence pass that closes every named gap with a concrete file and pins every changed gate manifest. Sister pattern: durable artifacts settle the work; here they keep the work parked.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://startaitools.com/posts/name-the-single-authority-in-a-daily-pipeline/" rel="noopener noreferrer"&gt;name-the-single-authority-in-a-daily-pipeline&lt;/a&gt;: When a daily pipeline runs unobserved, every concern accumulates competing authorities; the cure is to name exactly one authority per concern. Decision-22 is the named authority here.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://startaitools.com/posts/link-public-surface-to-deployment-thesis/" rel="noopener noreferrer"&gt;link-public-surface-to-deployment-thesis&lt;/a&gt;: The publish-and-park pattern breaks the public-surface-to-deployment link on purpose; the cataloged post argues the opposite. Worth reading both before committing a migration.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&amp;lt;br&amp;gt;
{&amp;lt;br&amp;gt;
  &amp;amp;quot;&lt;a class="mentioned-user" href="https://dev.to/context"&gt;@context&lt;/a&gt;&amp;amp;quot;: &amp;amp;quot;&amp;lt;a href="https://schema.org"&amp;gt;https://schema.org&amp;lt;/a&amp;gt;&amp;amp;quot;,&amp;lt;br&amp;gt;
  &amp;amp;quot;@type&amp;amp;quot;: &amp;amp;quot;FAQPage&amp;amp;quot;,&amp;lt;br&amp;gt;
  &amp;amp;quot;mainEntity&amp;amp;quot;: [&amp;lt;br&amp;gt;
    {&amp;lt;br&amp;gt;
      &amp;amp;quot;@type&amp;amp;quot;: &amp;amp;quot;Question&amp;amp;quot;,&amp;lt;br&amp;gt;
      &amp;amp;quot;name&amp;amp;quot;: &amp;amp;quot;How do you park a refactor without abandoning it?&amp;amp;quot;,&amp;lt;br&amp;gt;
      &amp;amp;quot;acceptedAnswer&amp;amp;quot;: {&amp;lt;br&amp;gt;
        &amp;amp;quot;@type&amp;amp;quot;: &amp;amp;quot;Answer&amp;amp;quot;,&amp;lt;br&amp;gt;
        &amp;amp;quot;text&amp;amp;quot;: &amp;amp;quot;Five invariants hold: the work lands as an atomic fast-forward push, the gate suite pins to the merged commit (including an independent reviewer), no production mutation happens at ship time, a &amp;amp;#39;do not cut over&amp;amp;#39; decision record lands in the repo, and a successor repo gives the parked work somewhere forward to go. Drop any one and the parked work becomes abandoned in slow motion.&amp;amp;quot;&amp;lt;br&amp;gt;
      }&amp;lt;br&amp;gt;
    },&amp;lt;br&amp;gt;
    {&amp;lt;br&amp;gt;
      &amp;amp;quot;@type&amp;amp;quot;: &amp;amp;quot;Question&amp;amp;quot;,&amp;lt;br&amp;gt;
      &amp;amp;quot;name&amp;amp;quot;: &amp;amp;quot;When should you delay a production cutover after a green merge?&amp;amp;quot;,&amp;lt;br&amp;gt;
      &amp;amp;quot;acceptedAnswer&amp;amp;quot;: {&amp;lt;br&amp;gt;
        &amp;amp;quot;@type&amp;amp;quot;: &amp;amp;quot;Answer&amp;amp;quot;,&amp;lt;br&amp;gt;
        &amp;amp;quot;text&amp;amp;quot;: &amp;amp;quot;Delay when a green badge sits on a moving branch, when the cutover and rollback share one failure domain, or when the &amp;amp;#39;do not cut over&amp;amp;#39; decision has nowhere to live. Parking keeps the new code on a feature branch with a pinned badge, so the deploy step can be rehearsed independently before the swap.&amp;amp;quot;&amp;lt;br&amp;gt;
      }&amp;lt;br&amp;gt;
    },&amp;lt;br&amp;gt;
    {&amp;lt;br&amp;gt;
      &amp;amp;quot;@type&amp;amp;quot;: &amp;amp;quot;Question&amp;amp;quot;,&amp;lt;br&amp;gt;
      &amp;amp;quot;name&amp;amp;quot;: &amp;amp;quot;Why not merge to main and cut over later?&amp;amp;quot;,&amp;lt;br&amp;gt;
      &amp;amp;quot;acceptedAnswer&amp;amp;quot;: {&amp;lt;br&amp;gt;
        &amp;amp;quot;@type&amp;amp;quot;: &amp;amp;quot;Answer&amp;amp;quot;,&amp;lt;br&amp;gt;
        &amp;amp;quot;text&amp;amp;quot;: &amp;amp;quot;A green badge on main sits on a moving target that any reset invalidates retroactively, a cutover welded to a merge is one failure domain, and a &amp;amp;#39;do not cut over&amp;amp;#39; decision has no place to live when main is the act of cutting over. Parking keeps work, gate results, and decision on separate durable artifacts.&amp;amp;quot;&amp;lt;br&amp;gt;
      }&amp;lt;br&amp;gt;
    }&amp;lt;br&amp;gt;
  ]&amp;lt;br&amp;gt;
}&amp;lt;/p&amp;gt;
&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>releaseengineering</category>
      <category>devops</category>
      <category>cicd</category>
    </item>
    <item>
      <title>Team-Page Ordering Is a Release Decision</title>
      <dc:creator>Jeremy Longshore</dc:creator>
      <pubDate>Wed, 30 Sep 2026 11:30:11 +0000</pubDate>
      <link>https://dev.to/jeremy_longshore/team-page-ordering-is-a-release-decision-3el6</link>
      <guid>https://dev.to/jeremy_longshore/team-page-ordering-is-a-release-decision-3el6</guid>
      <description>&lt;p&gt;A new Legal Counsel profile landed at the bottom of the team page yesterday. Heather Johnson was the most consequential reader-facing contact on the page, and the page put her last. The fix shipped thirty-four minutes later as v4.4.1, because team-page ordering is a release decision, not a content decision, and treating it as one is what keeps a canonical team page authoritative across eight linked properties.&lt;/p&gt;

&lt;h2&gt;
  
  
  How should team pages be ordered?
&lt;/h2&gt;

&lt;p&gt;Team-page ordering should put the highest-value reader-facing contact first, after the founder. For a regulated AI practice that is Legal Counsel; for a design studio it might be the creative leads. The rule is short: name who readers are most likely to need, list them in that order, document the rule, and reorder when a new profile lands.&lt;/p&gt;

&lt;h2&gt;
  
  
  What shipped and what did not
&lt;/h2&gt;

&lt;p&gt;The intent-solutions-landing repo (the source of truth for the company team surface at intentsolutions.io/about/#team) shipped v4.4.0 at 18:49 CDT. The PR added seven team photos, a new &lt;code&gt;team.json&lt;/code&gt; roster, a &lt;code&gt;HeatherJohnson.astro&lt;/code&gt; profile page, and an updated footer link. The original reviewer caught the ordering at 19:18, while the v4.4.0 deploy was still propagating through the cache. The reviewer did not flag the order as "wrong." They flagged it as "wrong for the audience the page is about to serve." That distinction is what the rest of this post defends. The roster looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Jeremy Longshore"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Founder"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Opeyemi Adeyemi"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Operations"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Pablo Hernandez"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Engineering"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Max Sheahan"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Education"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Tim Yates"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AI Engineering"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Tolulope Bakare"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Engineering"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Heather Johnson"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Legal Counsel"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The order is hire chronology: founder first, then each subsequent hire in the order they joined. Heather was the most recent hire, so she landed at the bottom. That is the second-most-reasonable default after alphabetical, and it is also wrong for a regulated AI practice where the counsel is the only person on the page a reader might need to reach for a privacy question, a partnership inquiry, or a compliance ask. Hire-chronology works on small teams where seniority is the only signal a reader has. Once a reader needs to find one specific person, it works against them.&lt;/p&gt;

&lt;p&gt;v4.4.1 reordered the file thirty-four minutes later:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Jeremy Longshore"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Founder"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Heather Johnson"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Legal Counsel"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Opeyemi Adeyemi"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Operations"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Pablo Hernandez"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Engineering"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Max Sheahan"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Education"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Tim Yates"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AI Engineering"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Tolulope Bakare"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Engineering"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The diff is six lines moved up. The semantic change is that the page now answers the question a reader is most likely to bring to it, before they have to scroll past six other faces.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not the obvious approach?
&lt;/h2&gt;

&lt;p&gt;Two reasonable defaults existed. The first was alphabetical, which we considered and rejected as a draft. The second was the as-hired ordering we actually shipped: it is a content decision masquerading as a release decision. The team page is the canonical contact surface for the whole estate, and a reader does not care who joined first. They care who can answer their question.&lt;/p&gt;

&lt;p&gt;The third option, leaving the order to whoever maintains the page next, is the one that drifts. Within three months, someone adds a contractor. Then a summer intern. Then the intern moves up but stays where they are. The team page stops being authoritative and starts being a snapshot.&lt;/p&gt;

&lt;p&gt;We chose the role-priority ordering with an explicit rule: after the founder, the page lists people in the order a reader is most likely to need them. Legal first, then operations, then the engineering and education roles together, then everything else. The rule is short enough to fit on a sticky note, and short enough that a maintainer three jobs from now will still apply it.&lt;/p&gt;

&lt;p&gt;The role-priority rule is not universal. It is the right rule for a regulated AI practice where the counsel is the highest-value contact. It would be the wrong rule for a design studio where the reader wants to see the creative leads first. The point is not that role-priority is the answer. The point is that the answer is a rule with a name, not a one-off decision the original author made and forgot to document.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 30-minute footer sweep
&lt;/h2&gt;

&lt;p&gt;The same moment v4.4.0 landed, eight repos each picked up a new "Our team" footer link pointing at &lt;code&gt;intentsolutions.io/about/#team&lt;/code&gt;. The sweep window was 18:59 to 19:29 CDT, roughly thirty minutes. Six of those repos are public landing surfaces (&lt;code&gt;intent-demos&lt;/code&gt;, &lt;code&gt;omarchy&lt;/code&gt;, &lt;code&gt;diagnostic-pro&lt;/code&gt;, &lt;code&gt;startaitools&lt;/code&gt;, &lt;code&gt;hustle&lt;/code&gt;, &lt;code&gt;claude-code-plugins&lt;/code&gt;). The seventh is &lt;code&gt;intent-solutions-landing&lt;/code&gt; itself, whose team.json is the source of truth. The eighth is &lt;code&gt;now-lms&lt;/code&gt;, which also renders its own team profile and shipped the CI gate.&lt;/p&gt;

&lt;p&gt;The footer change per repo was mechanical. Each inserted a single line into its existing footer list, between "About" and the next item:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://intentsolutions.io/about/#team"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Our team&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The insertions are byte-different per repo because each footer is a different framework (&lt;code&gt;site/index.html&lt;/code&gt; for the static HTML sites, &lt;code&gt;Footer.tsx&lt;/code&gt; for diagnostic-pro, &lt;code&gt;layouts/partials/footer.html&lt;/code&gt; for the Hugo build, &lt;code&gt;src/app/(public)/page.tsx&lt;/code&gt; for the Next.js hustle app, &lt;code&gt;marketplace/src/layouts/BaseLayout.astro&lt;/code&gt; for the Astro marketplace). The pattern is identical. Eight repos, one anchor, one canonical URL, one PR opened in each repo on the same minute by the same author.&lt;/p&gt;

&lt;p&gt;The mechanics matter because they explain why the ordering hotfix had to ship in the same hour. When footers sweep together, the page they point at becomes the contract for the whole estate. By 19:00 CDT, every footer in the estate was pointing at a team page that had Heather at the bottom. The hotfix is not a content correction. It is a release of a new public fact, and the new public fact is the ordering on the page those eight footers resolve to. Waiting twenty-four hours would have meant twenty-four hours of every visitor to any of those eight sites seeing a team page with a regulated-AI Legal Counsel buried seventh.&lt;/p&gt;

&lt;p&gt;The rollback path was open if v4.4.1 had broken the build: revert the &lt;code&gt;team.json&lt;/code&gt; diff, cut v4.4.2, redeploy. Eight footers would have re-resolved to the v4.4.0 ordering for the duration of the rollback. That is the cost of treating a team page like a release: you owe it a rollback, and a rollback is cheap when the change is six lines of JSON moved up.&lt;/p&gt;

&lt;p&gt;The alternative, batching the hotfix into the next deploy window, was the original instinct. Batching would have meant a coordinated revert of the eight footers, which is its own release with its own rollback path. The hotfix was cheaper than the batch. That is the math that decides whether something ships same-day or waits.&lt;/p&gt;

&lt;h2&gt;
  
  
  The CI gate: check_estate_bar.py
&lt;/h2&gt;

&lt;p&gt;Once eight repos link to one URL, that URL becomes load-bearing in a way a single-site URL never is. A rename to &lt;code&gt;/team/&lt;/code&gt; or a layout shift that breaks the &lt;code&gt;#team&lt;/code&gt; anchor would silently rot every footer in the estate. The now-lms repo shipped &lt;code&gt;scripts/check_estate_bar.py&lt;/code&gt; in the same hour, a 79-line Python check that hits the canonical URL and verifies the anchor still resolves to a non-empty team roster. The gate is intentionally minimal. It does not parse the ordering. It does not check the photo count. It checks the load-bearing claim: this URL is a roster, and the roster is present.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ESTATE_TEAM_URL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DEFAULT_URL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User-Agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;check-estate-bar/1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;soup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BeautifulSoup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;html.parser&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;anchor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;soup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;team&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;anchor&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;FAIL: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; has no #team anchor&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;members&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;anchor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attrs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data-team-member&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;members&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;FAIL: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; #team has no roster&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PASS: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; #team has &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;members&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; members&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The check is a deterministic fact: the URL resolves, the anchor resolves, the roster is non-empty. It does not check ordering, because ordering is a release decision and we already made the release. It checks that the page is still authoritative. That is the gate's job.&lt;/p&gt;

&lt;p&gt;The check is wired into now-lms CI as a required step. The other seven repos do not run it yet; they each link to the same URL and would each fail in the same way if the page rotted. Wiring them all is the next bead.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this looks like at three months
&lt;/h2&gt;

&lt;p&gt;Without the CI gate, the page drifts. A volunteer contributor renames the anchor for SEO. A designer moves the roster into a tabbed component. An image lazy-loads wrong and the team section renders empty on the first paint. None of those changes break the page locally. They all break the eight footers silently, because the footers still resolve to a 200 and the link still works, but the reader who clicks "Our team" lands on a page that does not answer their question.&lt;/p&gt;

&lt;p&gt;We have lived this pattern before on the same estate. A blog post URL moved in March and four linkers rotted quietly until a reader complained in July. An "Our partners" anchor moved under a redesign in April and the cross-link from the partner portal went to a blank section for the better part of a quarter. The pattern is consistent: a small, semantic change to a canonical page is invisible at the page itself and silently broken at every other surface that links to it.&lt;/p&gt;

&lt;p&gt;The CI gate catches two of those three failure modes. The third is a renderer bug, and we have not yet decided whether the gate should expand to cover it. For now, the gate is a presence check, not a quality check. That is the right scope for a 79-line script. Expanding it into a full render check means either a headless browser (slow, flaky, expensive) or a snapshot regression (cheap, brittle, drifts with any visual change). The presence check is the floor that catches the worst class of bug at zero ongoing cost.&lt;/p&gt;

&lt;p&gt;The other thing a CI gate does is give the next maintainer permission to push back. Without the gate, the only signal that "the team page is load-bearing" is the eight footers, and a maintainer three jobs from now will not count the footers. With the gate, the dependency is a line in CI: "this URL must resolve to a roster." That is a contract someone can read, and contracts outlive institutional memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "estate anchor" actually means
&lt;/h2&gt;

&lt;p&gt;An estate anchor is a URL that other properties depend on as a contract rather than as a reference. A reference is a link a reader clicks if they are curious. A contract is a link that is supposed to resolve to a specific thing, and the thing it resolves to is part of what the linking page is asserting.&lt;/p&gt;

&lt;p&gt;The footer sweep turned &lt;code&gt;intentsolutions.io/about/#team&lt;/code&gt; from a reference into a contract. Before the sweep, the page was a page. After the sweep, eight footers were asserting "click here and find our team." The assertion is the contract. If a reader clicks and does not find a team, the footer has lied to them, and the lie is silent because the footer still resolves to a 200.&lt;/p&gt;

&lt;p&gt;Most estates cross the reference-to-contract line without noticing. There is a docs page that points at a pricing surface, a marketing page that references a changelog, and a partner directory that cross-links a contact page. Each link is small. In aggregate, each is a contract. The CI gate is the moment a team acknowledges the contract exists.&lt;/p&gt;

&lt;p&gt;The cost of acknowledging the contract is small. The check is 79 lines. The wiring is one line per repo. The maintenance is one URL to remember. The benefit is that the next push to a wired repo that renames the anchor or moves the roster into a tabbed component gets a red CI run and a one-sentence error explaining why their change broke the estate. The remaining seven footers still depend on the URL, so wiring the gate into every one of them is the next bead; until that ships, a rename on intent-solutions-landing itself will only be caught on the next gated push. That is enough to make the right decision the easy one.&lt;/p&gt;

&lt;p&gt;The next time a similar pattern comes up on the estate (a new partner joins the directory, a new pricing tier appears, a new compliance doc publishes) the discipline is already there. Same-day fix if the canonical surface changes. CI gate before the third link points at it. The team page was the first anchor in the estate to get the full treatment. The pattern is now load-bearing for every anchor that comes after it.&lt;/p&gt;

&lt;p&gt;That is the lesson. A team page is a page. A team page that eight footers depend on is a contract. The cost of treating it like one is one extra script and one extra hour.&lt;/p&gt;

&lt;h2&gt;
  
  
  Also shipped
&lt;/h2&gt;

&lt;p&gt;The rest of the day's work that does not fit the team-page finding:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;now-lms&lt;/code&gt; (#125) shipped the estate-bar check plus the matching team profile rendering for Heather, with the same ordering rule as the canonical surface.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;intent-os&lt;/code&gt; shipped the whiteglove distribution packet (3516 lines, nine print PDFs) and the matching ownership verification records.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hustle&lt;/code&gt; v3.3.7 and &lt;code&gt;startaitools&lt;/code&gt; v1.21.14 auto-bumped on the same day as the team-link fix landing in each repo.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;omarchy&lt;/code&gt; refreshed its public plugin facts from the GitHub API (generated content only, no semantic change).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The discipline, generalized
&lt;/h2&gt;

&lt;p&gt;The team page is one canonical surface among several on this estate. The partner directory is another. The pricing page is a third. The published-changelog index is a fourth. Every one of them is a page that other repos link to, and every one of them has the same problem: a small, semantic change is invisible at the page and silently broken everywhere else.&lt;/p&gt;

&lt;p&gt;The team-page fix generalizes to a rule: when a single canonical surface becomes load-bearing across the estate, treat every edit to it as a release. The release gets a version bump, a changelog entry, a same-day hotfix window, and a CI gate that proves the URL still resolves to what the linkers expect. None of that is novel. It is the same discipline every API publishes under. The point is that a marketing page deserves the same treatment the moment it becomes an estate anchor, and most pages become estate anchors without anyone noticing.&lt;/p&gt;

&lt;p&gt;The reason this matters for a team page specifically is that the failure mode is invisible to the team and visible only to the reader. The team sees the page render correctly in their browser. The reader sees a page where the person they came for is seventh. The cost of getting the ordering wrong is paid by people who never show up in your bug tracker.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use this
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Treat team-page ordering as a release decision. Pick a rule short enough for the next maintainer to apply without asking, document it once, and reorder on the day a new profile lands.&lt;/li&gt;
&lt;li&gt;When you turn a single-site URL into an estate anchor, ship a deterministic check that the URL still resolves to the thing eight footers expect. 79 lines of Python is enough for the first gate.&lt;/li&gt;
&lt;li&gt;Order the canonical team page by the question a reader is most likely to bring, not by hire date and not by alphabet. The page is a contact surface, not a roster. The exact ordering depends on what the reader is most likely to want; the discipline is that the ordering is named, defended, and written down next to the file.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why should team-page ordering be treated as a release decision?
&lt;/h3&gt;

&lt;p&gt;A team page becomes load-bearing the moment multiple footer links point at it. Once eight footers assert "click here and find our team," the ordering is a public fact the estate is publishing, not a content choice. A same-day hotfix is cheaper than batching, because batching would mean a coordinated revert of every footer that points at the page. The page is a contract that other sites depend on, and contracts get release discipline.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is an estate anchor?
&lt;/h3&gt;

&lt;p&gt;An estate anchor is a URL that other properties depend on as a contract rather than as a reference. A reference is a link a reader clicks if curious; a contract is a link that should resolve to a specific thing, and the thing it resolves to is part of what the linking page is asserting. If the anchor breaks, every linking surface silently lies because the link still returns a 200 but the reader does not find what they were promised.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do you keep a team page authoritative across multiple sites?
&lt;/h3&gt;

&lt;p&gt;Ship a deterministic CI gate that hits the canonical URL and verifies the anchor still resolves to a non-empty roster. The check_estate_bar.py gate is 79 lines of Python and runs as a required CI step in &lt;code&gt;now-lms&lt;/code&gt;. Wiring it into every other linking repo is the part that catches silent drift when a designer moves the roster into a tabbed component or someone renames the anchor.&lt;/p&gt;

&lt;p&gt;{&lt;br&gt;
  "&lt;a class="mentioned-user" href="https://dev.to/context"&gt;@context&lt;/a&gt;": "&lt;a href="https://schema.org" rel="noopener noreferrer"&gt;https://schema.org&lt;/a&gt;",&lt;br&gt;
  "@type": "FAQPage",&lt;br&gt;
  "mainEntity": [&lt;br&gt;
    {&lt;br&gt;
      "@type": "Question",&lt;br&gt;
      "name": "Why should team-page ordering be treated as a release decision?",&lt;br&gt;
      "acceptedAnswer": {&lt;br&gt;
        "@type": "Answer",&lt;br&gt;
        "text": "A team page becomes load-bearing the moment multiple footer links point at it. Once eight footers assert 'click here and find our team,' the ordering is a public fact the estate is publishing, not a content choice. A same-day hotfix is cheaper than batching, because batching would mean a coordinated revert of every footer that points at the page. The page is a contract that other sites depend on, and contracts get release discipline."&lt;br&gt;
      }&lt;br&gt;
    },&lt;br&gt;
    {&lt;br&gt;
      "@type": "Question",&lt;br&gt;
      "name": "What is an estate anchor?",&lt;br&gt;
      "acceptedAnswer": {&lt;br&gt;
        "@type": "Answer",&lt;br&gt;
        "text": "An estate anchor is a URL that other properties depend on as a contract rather than as a reference. A reference is a link a reader clicks if curious; a contract is a link that should resolve to a specific thing, and the thing it resolves to is part of what the linking page is asserting. If the anchor breaks, every linking surface silently lies because the link still returns a 200 but the reader does not find what they were promised."&lt;br&gt;
      }&lt;br&gt;
    },&lt;br&gt;
    {&lt;br&gt;
      "@type": "Question",&lt;br&gt;
      "name": "How do you keep a team page authoritative across multiple sites?",&lt;br&gt;
      "acceptedAnswer": {&lt;br&gt;
        "@type": "Answer",&lt;br&gt;
        "text": "Ship a deterministic CI gate that hits the canonical URL and verifies the anchor still resolves to a non-empty roster. The check_estate_bar.py gate is 79 lines of Python and runs as a required CI step in &lt;code&gt;now-lms&lt;/code&gt;. Wiring it into every other linking repo is the part that catches silent drift when a designer moves the roster into a tabbed component or someone renames the anchor."&lt;br&gt;
      }&lt;br&gt;
    }&lt;br&gt;
  ]&lt;br&gt;
}&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Posts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://startaitools.com/posts/use-the-primitive-not-the-patch-codeql/" rel="noopener noreferrer"&gt;Use the Primitive, Not the Patch&lt;/a&gt; (the same-day-sweep discipline, applied to a security primitive rather than a team page).&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://startaitools.com/posts/scope-federated-tailscale-trust-to-auth-keys/" rel="noopener noreferrer"&gt;Scope Federated Tailscale Trust to Auth Keys&lt;/a&gt; (federating one identity surface across the same eight-repo footprint, with the same anchor-page release posture).&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://startaitools.com/posts/pin-the-installer-and-add-a-renewer/" rel="noopener noreferrer"&gt;Pin the Installer and Add a Renewer&lt;/a&gt; (a named rule plus a CI gate that catches silent drift, the same shape as &lt;code&gt;check_estate_bar.py&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>architecture</category>
      <category>devops</category>
      <category>releaseengineering</category>
    </item>
    <item>
      <title>Tailscale Federated Trust: Scope to Auth Keys, Not All</title>
      <dc:creator>Jeremy Longshore</dc:creator>
      <pubDate>Sun, 27 Sep 2026 11:30:11 +0000</pubDate>
      <link>https://dev.to/jeremy_longshore/tailscale-federated-trust-scope-to-auth-keys-not-all-3gm1</link>
      <guid>https://dev.to/jeremy_longshore/tailscale-federated-trust-scope-to-auth-keys-not-all-3gm1</guid>
      <description>&lt;h1&gt;
  
  
  Tailscale Federated Trust: Scope to Auth Keys, Not All
&lt;/h1&gt;

&lt;p&gt;A Tailscale federated trust hands an external identity (in my case, GitHub Actions OIDC) an API token whose reach is governed by a &lt;code&gt;scope&lt;/code&gt; field on the trust record. The default is &lt;code&gt;['all']&lt;/code&gt;, which gives that external identity every API the underlying token can reach. If the token is account-admin, your CI runner now is too.&lt;/p&gt;

&lt;p&gt;I had 18 deploy trusts wired that way. Every one of them creates a short-lived auth key to land a build on the VPS over Tailscale SSH. None of them need anything else. On 2026-09-25 I narrowed every one to &lt;code&gt;scope:['auth_keys']&lt;/code&gt;, re-encrypted the SOPS secrets bundle, and proved it on a real &lt;code&gt;jeremylongshore.com&lt;/code&gt; production deploy.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a federated trust actually is
&lt;/h2&gt;

&lt;p&gt;Tailscale's term for "let an external identity mint a short-lived Tailscale API token" is a &lt;strong&gt;federated trust&lt;/strong&gt;: a record that maps an OIDC subject (or a SAML subject, or a workload identity federation principal) onto a Tailscale API token. The trust is created once by an admin. The external identity uses it on every CI run to mint a fresh, narrowly-scoped auth key. The fresh auth key is what actually gets used to bring a runner onto the tailnet.&lt;/p&gt;

&lt;p&gt;The trust does not move packets. It only mints keys. The runner uses the key to register a node, the node runs the deploy, the node goes away when the key expires.&lt;/p&gt;

&lt;p&gt;A trust record stored on Tailscale's side looks roughly like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"trust_abc123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"github"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"subject"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"repo:intent-solutions-io/jeremylongshore.com:environment:production"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scopes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"all"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"token_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tk_xyz789"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"created_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-04-12T18:22:01Z"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;scopes&lt;/code&gt; field is what the trust is allowed to ask the token to do. It is not what the runner gets to do once the runner is on the tailnet. Those are two different layers, and a &lt;code&gt;['all']&lt;/code&gt; trust means the trust itself is allowed to ask the token to do anything, on every CI run, until someone narrows it.&lt;/p&gt;

&lt;p&gt;The shape of the trust matters because the trust gets a token, and the token has scope. If the trust was created with an account-admin token and &lt;code&gt;scope:['all']&lt;/code&gt;, the OIDC subject inherits that token's full reach every time the trust is exercised. The fact that the runner itself only needs &lt;code&gt;auth_keys&lt;/code&gt; does not constrain what the trust can be tricked into minting.&lt;/p&gt;

&lt;h2&gt;
  
  
  The default that bit me
&lt;/h2&gt;

&lt;p&gt;The Tailscale CLI's &lt;code&gt;tailnet set-trust-credentials&lt;/code&gt; (and the web UI's equivalent) defaults &lt;code&gt;scope&lt;/code&gt; to &lt;code&gt;['all']&lt;/code&gt; when you do not pass it. Most of the docs and most of the tutorials do not tell you that, because most of them are written for the "set it up once and forget it" case. My case was 18 separate repos, each one a deploy, each one created when I was hurrying. The hurrying is why they were all &lt;code&gt;['all']&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The whole change is one line in the trust config.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;   trust:
     provider: github
     subject: repo:intent-solutions-io/&amp;lt;repo&amp;gt;:environment:production
&lt;span class="gd"&gt;-    scopes:
-      - all
&lt;/span&gt;&lt;span class="gi"&gt;+    scopes:
+      - auth_keys
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only change is &lt;code&gt;scopes: [auth_keys]&lt;/code&gt;. The OIDC subject is unchanged. The token it maps onto is unchanged. The runner still gets to mint an auth key. It no longer gets to mint anything else.&lt;/p&gt;

&lt;p&gt;In SOPS, the edit lands in &lt;code&gt;ops/host/secrets/secrets.prod.sops.yaml&lt;/code&gt;, gets re-encrypted with &lt;code&gt;sops update&lt;/code&gt;, and the next deploy reads the new scope. The trust itself is updated on Tailscale's side by a follow-up &lt;code&gt;tailscale set-trust-credentials --scopes=auth_keys&lt;/code&gt; call, which Tailscale reconciles with the SOPS record. The two stay in sync because both are produced from the same workflow. The &lt;code&gt;secrets.prod.sops.yaml&lt;/code&gt; re-encrypt was the headline change in 62f100aa; the per-trust config edits in &lt;code&gt;intent-os/ops/deploy/&lt;/code&gt; followed in the same commit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is not paranoia
&lt;/h2&gt;

&lt;p&gt;Two reasons this matters beyond hygiene.&lt;/p&gt;

&lt;p&gt;First, the trust is the long-lived artifact. The token underneath can be rotated; the trust persists. If the trust says &lt;code&gt;['all']&lt;/code&gt;, every rotation of the token keeps the same reach. The scope is what does not get narrower over time without deliberate action. You set it on day one, then forget, and the day you forget is the failure mode.&lt;/p&gt;

&lt;p&gt;Second, the blast radius of an OIDC mis-substitution is bigger than people assume. GitHub Actions lets you constrain an environment's deployment branch, required reviewers, and protection rules, but it does not let you constrain which subject string the Actions OIDC token actually carries on a particular run if the workflow file is wrong. A workflow that accidentally trusts a fork PR will issue an OIDC token whose subject matches the trust's subject regex, and the trust will mint whatever its scope allows. &lt;code&gt;['all']&lt;/code&gt; is the worst-case scope for that failure mode. &lt;code&gt;['auth_keys']&lt;/code&gt; is the floor: even a misrouted OIDC exchange only ever produces a key, and the key lands on a tailnet ACL that the runner still has to walk through.&lt;/p&gt;

&lt;h2&gt;
  
  
  The proof
&lt;/h2&gt;

&lt;p&gt;The way I prove a trust change actually works is to run a real production deploy after the change. For &lt;code&gt;jeremylongshore.com&lt;/code&gt;, that is run 36106653875 on GitHub Actions. The deploy job:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Exchanges the OIDC token against the trust, asks for an auth key.&lt;/li&gt;
&lt;li&gt;Uses the auth key to bring the runner onto the tailnet as a node tagged &lt;code&gt;tag:ci&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;SSHes to the VPS as the deploy user, lands the build, exits.&lt;/li&gt;
&lt;li&gt;The auth key expires. The runner node drops off the tailnet.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The shape of step 1 looks like this in the deploy step (paraphrased, not the literal workflow):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Bring runner onto tailnet&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;ACTIONS_ID_TOKEN_REQUEST_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GH_OIDC_TOKEN }}&lt;/span&gt;
    &lt;span class="na"&gt;TS_AUTHKEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.authkey.outputs.key }}&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;curl -fsSL https://tailscale.com/install.sh | sh&lt;/span&gt;
    &lt;span class="s"&gt;sudo tailscale up --authkey="$TS_AUTHKEY" --hostname="gh-runner-$GITHUB_RUN_ID" --tags=tag:ci&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SSH to VPS and deploy&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;appleboy/ssh-action@v1&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;intentsolutions&lt;/span&gt;
    &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy&lt;/span&gt;
    &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;cd /srv/jeremylongshore &amp;amp;&amp;amp; git pull --ff-only &amp;amp;&amp;amp; ./deploy.sh&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The auth key is fetched first, separately, from Tailscale's federated trust exchange endpoint. The runner then uses that key for &lt;code&gt;tailscale up&lt;/code&gt;. The deploy step SSHes to the VPS as the deploy user, lands the build, exits. The runner node drops off when the auth key expires.&lt;/p&gt;

&lt;p&gt;After the &lt;code&gt;scopes: [auth_keys]&lt;/code&gt; change, run 36106653875 completed end-to-end in 41 seconds. The runner registered, the deploy shipped, the node tore down. The runner could reach nothing beyond an auth key. I verified that by calling &lt;code&gt;tailscale set-acl&lt;/code&gt; from inside the same job and getting this back:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;tailscale set-acl &lt;span class="nt"&gt;--acl-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/tmp/empty.json
&lt;span class="gp"&gt;Error: HTTP 403: scope_mismatch (trust_scopes=auth_keys;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;required&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;acl&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the proof. A deploy that does not try &lt;code&gt;set-acl&lt;/code&gt; does not notice the change; a misrouted OIDC exchange that does try it now fails closed at the trust, before the token is even consulted. The runner gets back a 403 it can log and alert on, which is what you want: a loud refusal, not a silent partial success.&lt;/p&gt;

&lt;p&gt;The full sweep was 18 deploy trusts across &lt;code&gt;intent-os&lt;/code&gt;, &lt;code&gt;braves-booth&lt;/code&gt;, &lt;code&gt;diagnostic-pro&lt;/code&gt;, &lt;code&gt;hustle&lt;/code&gt;, &lt;code&gt;startaitools&lt;/code&gt;, &lt;code&gt;tonsofskills&lt;/code&gt;, and the &lt;code&gt;jeremylongshore.com&lt;/code&gt; site. The Omarchy one needed an extra step: that trust had been deleted and had to be recreated with its immutable OIDC subject read from GitHub, not pasted in (fd2ba8f9). The other 17 were a &lt;code&gt;sops&lt;/code&gt; re-encrypt and a config edit. The deploy pattern is the same; only the OIDC subject string and the tag differ per trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not just leave scope at all and rely on ACL
&lt;/h2&gt;

&lt;p&gt;Because ACL is a different layer and they do different jobs. The trust scope controls what the trust can do at the trust-mint boundary. The tailnet ACL controls what an already-on-the-tailnet node can reach. If you leave &lt;code&gt;scope:['all']&lt;/code&gt; and rely on ACL to keep the runner pinned, you have moved the only thing protecting you into a layer that the runner bypasses before it gets there.&lt;/p&gt;

&lt;p&gt;For my deploys the ACL layer was also locked. The relevant &lt;code&gt;tag:ci&lt;/code&gt; rule from the tailnet ACL is roughly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "tagOwners": {"tag:ci": ["autogroup:admin"]},
  "acls": [
    {
      "action": "accept",
      "src": ["tag:ci"],
      "dst": ["tag:deploy-vps:22"]
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That rule pins &lt;code&gt;tag:ci&lt;/code&gt; to SSH-only access to the deploy user on the VPS. The runner cannot reach any other node, cannot reach the admin console, cannot make API calls that go through the tailnet. So even an unscoped &lt;code&gt;['all']&lt;/code&gt; trust would have been pinned down by ACL once the runner registered. The trust scope and the ACL are belt and suspenders, not belt or suspenders. I want both. The narrower trust scope is also the change that survives token rotation, which the ACL does not. Rotate the underlying Tailscale API token every 90 days and the trust scope stays &lt;code&gt;auth_keys&lt;/code&gt; automatically, because the scope is on the trust, not on the token.&lt;/p&gt;

&lt;p&gt;There is also a third layer people forget about: the Tailscale admin console itself. An account-admin API key minted through a &lt;code&gt;['all']&lt;/code&gt; trust can call &lt;code&gt;tailscale set-acl&lt;/code&gt; against the entire tailnet, including deleting or rewriting ACLs. That is not "the runner touches a node." That is "the runner rewrites the rule that decides what nodes can touch." The trust scope is what stops that path before it starts.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the work went
&lt;/h2&gt;

&lt;p&gt;The session digest for the day shows the bulk of the operator work landed with MiniMax M3 (the bead triage, the sweep agents, the evidence filing). The trust scope rewrite itself was a single line repeated 18 times, but the design of "what scope to set, on what trust, with what proof" came out of a back-and-forth with Claude Opus 5.5. The Omarchy trust recreation, which needed the immutable OIDC subject read from GitHub rather than pasted in, was Claude Fable 5.1 because the change was small and well-bounded.&lt;/p&gt;

&lt;p&gt;The estate-graph proof isolation work in PRs 696, 697, and 698 was reviewed by Claude Sonnet 5 and shipped clean. The collaboration score for the day (0.275, 64 failure-to-fix transitions) is high because the estate sweep agent did the bulk of the bead triage, which generated a lot of small fix loops. The trust scope change itself was almost all up-front design and a one-line config edit per trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  Also shipped
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;VPS liveness sweep cleared (intent-os #681); two standing findings closed and a parked row acknowledged.&lt;/li&gt;
&lt;li&gt;Estate-graph proof isolation merged (#696, #697, #698): operator queries are now read-only and the validation path is isolated from operator state.&lt;/li&gt;
&lt;li&gt;Production smoke suite rewritten for the marketplace-site redesign (f80cc59ad): 132/132 chromium+webkit green on the post-deploy e2e.&lt;/li&gt;
&lt;li&gt;CI now fails when plugin verification scores drift from the validator (df3fdae75).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@intentsolutionsio/ccpi&lt;/code&gt; bumped to 3.0.0 on the Node 22 floor (not yet published to npm latest; publish is tag-triggered).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Use this
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;When you create a Tailscale federated trust, set &lt;code&gt;scopes: [auth_keys]&lt;/code&gt; explicitly. The default is &lt;code&gt;['all']&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Treat the trust scope and the tailnet ACL as two separate layers. Lock both. A &lt;code&gt;['all']&lt;/code&gt; trust behind a tight ACL is still worse than a &lt;code&gt;['auth_keys']&lt;/code&gt; trust behind the same ACL, because the trust scope is what survives token rotation.&lt;/li&gt;
&lt;li&gt;After you change a trust's scope, prove the change on a real production run, not just a &lt;code&gt;tailscale set-trust-credentials --dry-run&lt;/code&gt;. The dry run tells you the API accepted the call; only a deploy tells you the OIDC exchange still resolves.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is a Tailscale federated trust?
&lt;/h3&gt;

&lt;p&gt;A Tailscale &lt;strong&gt;federated trust&lt;/strong&gt; is a record that maps an external identity (GitHub Actions OIDC, SAML, or a workload identity federation principal) onto a Tailscale API token. The trust is created once by an admin. The external identity uses it on every CI run to mint a fresh, narrowly-scoped auth key. The fresh auth key is what actually brings a runner onto the tailnet; the trust itself only mints keys.&lt;/p&gt;

&lt;h3&gt;
  
  
  What does scope:['all'] actually grant on a federated trust?
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;scope&lt;/code&gt; field on the trust record governs what the trust can ask its mapped token to do. The default is &lt;code&gt;['all']&lt;/code&gt;, which gives the external identity every API that mapped token can reach. If that token is account-admin, the CI runner inherits that reach on every run, even if the runner itself only needs &lt;code&gt;auth_keys&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why not just rely on the tailnet ACL instead of narrowing the trust scope?
&lt;/h3&gt;

&lt;p&gt;The trust scope controls what the trust can do at the trust-mint boundary. The tailnet ACL controls what an already-on-the-tailnet node can reach. Leaving &lt;code&gt;scope:['all']&lt;/code&gt; and relying on ACL moves the only thing protecting you into a layer the runner bypasses before it gets there. A &lt;code&gt;['all']&lt;/code&gt; trust behind a tight ACL is still worse than a &lt;code&gt;['auth_keys']&lt;/code&gt; trust behind the same ACL, because the trust scope is what survives token rotation.&lt;/p&gt;

&lt;p&gt;{&lt;br&gt;
  "&lt;a class="mentioned-user" href="https://dev.to/context"&gt;@context&lt;/a&gt;": "&lt;a href="https://schema.org" rel="noopener noreferrer"&gt;https://schema.org&lt;/a&gt;",&lt;br&gt;
  "@type": "FAQPage",&lt;br&gt;
  "mainEntity": [&lt;br&gt;
    {&lt;br&gt;
      "@type": "Question",&lt;br&gt;
      "name": "What is a Tailscale federated trust?",&lt;br&gt;
      "acceptedAnswer": {&lt;br&gt;
        "@type": "Answer",&lt;br&gt;
        "text": "A Tailscale federated trust is a record that maps an external identity (GitHub Actions OIDC, SAML, or a workload identity federation principal) onto a Tailscale API token. The trust is created once by an admin. The external identity uses it on every CI run to mint a fresh, narrowly-scoped auth key. The fresh auth key is what actually brings a runner onto the tailnet."&lt;br&gt;
      }&lt;br&gt;
    },&lt;br&gt;
    {&lt;br&gt;
      "@type": "Question",&lt;br&gt;
      "name": "What does scope:['all'] actually grant on a federated trust?",&lt;br&gt;
      "acceptedAnswer": {&lt;br&gt;
        "@type": "Answer",&lt;br&gt;
        "text": "The scope field on the trust record governs what the trust can ask its mapped token to do. The default is ['all'], which gives the external identity every API that mapped token can reach. If that token is account-admin, the CI runner inherits that reach on every run, even if the runner itself only needs auth_keys."&lt;br&gt;
      }&lt;br&gt;
    },&lt;br&gt;
    {&lt;br&gt;
      "@type": "Question",&lt;br&gt;
      "name": "Why not just rely on the tailnet ACL instead of narrowing the trust scope?",&lt;br&gt;
      "acceptedAnswer": {&lt;br&gt;
        "@type": "Answer",&lt;br&gt;
        "text": "The trust scope controls what the trust can do at the trust-mint boundary. The tailnet ACL controls what an already-on-the-tailnet node can reach. Leaving scope:['all'] and relying on ACL moves the only thing protecting you into a layer the runner bypasses before it gets there. A ['all'] trust behind a tight ACL is still worse than a ['auth_keys'] trust behind the same ACL, because the trust scope is what survives token rotation."&lt;br&gt;
      }&lt;br&gt;
    }&lt;br&gt;
  ]&lt;br&gt;
}&lt;/p&gt;

&lt;h2&gt;
  
  
  Related
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://startaitools.com/posts/pin-the-installer-and-add-a-renewer/" rel="noopener noreferrer"&gt;Pin the Installer and Add a Renewer&lt;/a&gt;: the day's other big thread; pinning a published dependency and adding a cert renewer in the same pass.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://startaitools.com/posts/working-is-not-proven/" rel="noopener noreferrer"&gt;Working Is Not Proven&lt;/a&gt;: "every claim needs a shipped source and an executable proof"; the deploy run 36106653875 is exactly that proof.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://startaitools.com/posts/how-the-same-deploy-pattern-crossed-four-repos-in-one-week/" rel="noopener noreferrer"&gt;How the Same Deploy Pattern Crossed Four Repos in One Week&lt;/a&gt;: the deploy pattern at small scale; this post is what it looks like when the same pattern lands 18 times.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>cicd</category>
      <category>security</category>
      <category>tailscale</category>
      <category>githubactions</category>
    </item>
    <item>
      <title>Three Gates on Standard-User BitLocker State Observation</title>
      <dc:creator>Jeremy Longshore</dc:creator>
      <pubDate>Tue, 15 Sep 2026 11:30:13 +0000</pubDate>
      <link>https://dev.to/jeremy_longshore/three-gates-on-standard-user-bitlocker-state-observation-1h5l</link>
      <guid>https://dev.to/jeremy_longshore/three-gates-on-standard-user-bitlocker-state-observation-1h5l</guid>
      <description>&lt;h2&gt;
  
  
  The day started with a P1 on merge day
&lt;/h2&gt;

&lt;p&gt;Closing intent-blue-gold Epic 1+2 was supposed to be the easy part. The hard parts were the constraints, set in DOC-075/A03: a standard-user account on ARM64 Windows 11 gets PERMISSION_DENIED from the PowerShell Secure Boot and BitLocker surfaces. WMI is out. COM is out. Elevation is out. Anything that requires a privileged token is out. Everything since then has been about carving the safe space inside that envelope. BitLocker state observation, the volume census, the file inventory, the controller topology, the mapping registry, the criticality capture: each one is a new module boundary in the same constrained envelope.&lt;/p&gt;

&lt;p&gt;I ran Codex (GPT-5.6 Sol) read-only against the day's merge candidates on purpose. Eight sessions, 132 turns, 952 minutes on intent-blue-gold over the past week. The audit was not a polish pass. It was a closure gate. It surfaced three P1 blockers. Two of them were exactly the kind of failure the audit exists to catch.&lt;/p&gt;

&lt;p&gt;The three gates that have to hold together are: the observer contract, the bounded native provider, and the fixture-boundary authorization. Gate 3 was the one that slipped. The audit caught it on three failure modes at once, two of them the kind the audit exists to catch, and the post is mostly about what the audit found.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gate 1: the observer contract
&lt;/h2&gt;

&lt;p&gt;The observer contract is the seam between the constrained envelope and any code that wants to read BitLocker state. Anything that talks to &lt;code&gt;GetFveLogicalVolumeInformation&lt;/code&gt;-equivalent surfaces has to enter through this contract. Here is the seam in Go.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// BitlockerObserver is the standard-user entry point. It returns&lt;/span&gt;
&lt;span class="c"&gt;// State with the OBSERVED bit set only when the call ran through&lt;/span&gt;
&lt;span class="c"&gt;// the helper, the helper authenticated, and the fixture boundary&lt;/span&gt;
&lt;span class="c"&gt;// held. Anything else is OBSERVED=false, even if the bytes look&lt;/span&gt;
&lt;span class="c"&gt;// reasonable.&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;BitlockerObserver&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vol&lt;/span&gt; &lt;span class="n"&gt;VolumeRef&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// State has three meaningful bits:&lt;/span&gt;
&lt;span class="c"&gt;// OBSERVED  = we ran the native probe and got a result&lt;/span&gt;
&lt;span class="c"&gt;// CACHED    = we have a non-stale prior observation for this vol&lt;/span&gt;
&lt;span class="c"&gt;// UNAVAIL  = the probe ran but the OS returned access denied or&lt;/span&gt;
&lt;span class="c"&gt;//            empty; we treat that as no information, not as "off"&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;State&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Volume&lt;/span&gt;    &lt;span class="n"&gt;VolumeRef&lt;/span&gt;
    &lt;span class="n"&gt;Status&lt;/span&gt;    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="c"&gt;// protect_state strings, NOT raw OS bytes&lt;/span&gt;
    &lt;span class="n"&gt;Observed&lt;/span&gt;  &lt;span class="kt"&gt;bool&lt;/span&gt;
    &lt;span class="n"&gt;Cached&lt;/span&gt;    &lt;span class="kt"&gt;bool&lt;/span&gt;
    &lt;span class="n"&gt;Unavail&lt;/span&gt;   &lt;span class="kt"&gt;bool&lt;/span&gt;
    &lt;span class="n"&gt;Source&lt;/span&gt;    &lt;span class="n"&gt;ProbeSource&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The interesting bit is &lt;code&gt;Observed&lt;/code&gt;. A naive port of a privileged tool returns the OS bytes regardless of provenance. That is exactly what gets you a "we have a BitLocker reading" row that came from a non-authorized helper or from an arbitrary temp root. The observer contract refuses to label the result Observed unless every gate cleared. The byte string is still in &lt;code&gt;Status&lt;/code&gt;, but downstream code is supposed to ignore &lt;code&gt;Status&lt;/code&gt; when &lt;code&gt;Observed&lt;/code&gt; is false. That is the contract.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gate 2: the bounded native provider
&lt;/h2&gt;

&lt;p&gt;Gate 2 is the provider that does the actual syscall. Two constraints matter: it has to run in the standard-user process without UAC, without token impersonation, and without a helper service that takes elevation. It also has to refuse any caller who has not presented the authenticated helper boundary. The provider entry point.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;NativeProvider&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;QueryVolume&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vol&lt;/span&gt; &lt;span class="n"&gt;VolumeRef&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;helperBoundary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Authorized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vol&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// Fail closed: an unauthorized caller gets the same answer&lt;/span&gt;
        &lt;span class="c"&gt;// they would get from an unauthenticated probe. No detail,&lt;/span&gt;
        &lt;span class="c"&gt;// no exception type, no "near miss" leak.&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Volume&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;vol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Unavail&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;ErrBoundaryClosed&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;vol&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsFixtureAuthorized&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// The fixture boundary: even an authenticated helper can&lt;/span&gt;
        &lt;span class="c"&gt;// not cross outside the manifest-verified fixture. This&lt;/span&gt;
        &lt;span class="c"&gt;// is gate 3, but we enforce it at the provider entry to&lt;/span&gt;
        &lt;span class="c"&gt;// avoid a second code path that needs the same guarantee.&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Volume&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;vol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Unavail&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;ErrOutsideFixture&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;queryViaSyscall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vol&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;queryViaSyscall&lt;/code&gt; is the boring part. &lt;code&gt;FsctlEnumerateVolumeInformation&lt;/code&gt; with a &lt;code&gt;BITLOCKER_INFORMATION&lt;/code&gt; header, &lt;code&gt;IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS&lt;/code&gt; for layout, fall through to the registry path when the helper IPC returned access denied. The thing worth noticing is what comes BEFORE that: the two early returns. An unauthorized caller and an out-of-fixture caller both get &lt;code&gt;Unavail: true&lt;/code&gt; with &lt;code&gt;Observed: false&lt;/code&gt;. They get the same answer a probe that genuinely failed would have given. There is no signal that says "we are not telling you because of X."&lt;/p&gt;

&lt;p&gt;That is fail-closed by construction. The audit did not flag this gate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gate 3: the fixture-boundary authorization (the failure)
&lt;/h2&gt;

&lt;p&gt;Gate 3 was the failure. The file-inventory CLI is supposed to admit only the manifest-verified fixture. The fixture is a checked-in blob with a hash pinned in &lt;code&gt;fixture.manifest&lt;/code&gt;. Anything else is a synthetic root, and synthetic roots are test-only. The CLI was supposed to refuse a synthetic root at admission. Here is what the gate looks like.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Authorized root check. The CLI calls this before any work.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;FixtureAuth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Authorize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;manifest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;LoadManifest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="c"&gt;// no manifest, no authorization, fail closed&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;pinned&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;manifest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CanonicalRoot&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;pathEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pinned&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// Synthetic roots are valid in tests, but the production&lt;/span&gt;
        &lt;span class="c"&gt;// CLI is not a test. Production admission refuses them.&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ErrSyntheticRootRejected&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;manifest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HashMatches&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// The pinned root is the right path but the bytes don't&lt;/span&gt;
        &lt;span class="c"&gt;// match. That is a fixture drift, also a hard refusal.&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ErrFixtureDrift&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is what the code is supposed to do. Codex found that &lt;code&gt;prototypes/blue-windows/cmd/file-inventory/main.go:54-76&lt;/code&gt; accepts any directory containing a user-created marker and then scans its &lt;code&gt;Desktop&lt;/code&gt;, &lt;code&gt;Documents&lt;/code&gt;, &lt;code&gt;Downloads&lt;/code&gt;, and &lt;code&gt;Pictures&lt;/code&gt; children. A caller can add the marker under a live profile and receive filenames, sizes, and paths in the receipt. DOC-076:20-26 says the checked-in fixture is the only root authorized, and the authorization's synthetic-root-only constraint is supposed to bind production admission. The code did not bind it. The CLI was test-friendly and production-broken in the same binary.&lt;/p&gt;

&lt;p&gt;The minimal fix is to call &lt;code&gt;FixtureAuth.Authorize&lt;/code&gt; from &lt;code&gt;main.go:54-76&lt;/code&gt; before any traversal. The CLI keeps its test ergonomics because the test harness can register a synthetic root with the test-only &lt;code&gt;RegisterSynthetic&lt;/code&gt; hook, but the production binary refuses anything except the canonical fixture or a manifest-verified immutable fixture. That is what is shipping today. The audit caught it on merge day, the fix is small, and the constraint is the right one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The TOCTOU reparse replacement (gate 3, the second finding)
&lt;/h2&gt;

&lt;p&gt;The same audit flagged a separate failure in &lt;code&gt;scan.go:185-216&lt;/code&gt;: path-based &lt;code&gt;ReadDir&lt;/code&gt;, &lt;code&gt;Lstat&lt;/code&gt;, then recursive &lt;code&gt;ReadDir&lt;/code&gt;. A validated directory can be swapped for a reparse point mid-traversal. That is a classic TOCTOU path for read-only enumeration to follow attacker-controlled targets. The standard fix on Linux is &lt;code&gt;O_DIRECTORY | O_NOFOLLOW&lt;/code&gt;, then keep the file descriptor and enumerate from it. On Windows the equivalent is to open with &lt;code&gt;FILE_FLAG_OPEN_REPARSE_POINT&lt;/code&gt; and the standard share-mode set, capture the handle, and re-validate the reparse status from the handle before walking into children. The sketch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Linux side: open the directory once, hold the fd, refuse to walk&lt;/span&gt;
&lt;span class="c"&gt;// a reparse change observed post-open.&lt;/span&gt;
&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;unix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;O_RDONLY&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;unix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;O_DIRECTORY&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;unix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;O_NOFOLLOW&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;unix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;// Snapshot the reparse status at open time, then compare against&lt;/span&gt;
&lt;span class="c"&gt;// each entry's d_type before deciding to descend. (The full&lt;/span&gt;
&lt;span class="c"&gt;// re-validation lives in the production helper; the sketch is the&lt;/span&gt;
&lt;span class="c"&gt;// shape, not the implementation.)&lt;/span&gt;
&lt;span class="n"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;unix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getdents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Windows side is heavier (handle capture plus &lt;code&gt;DeviceIoControl(FSCTL_GET_REPARSE_POINT)&lt;/code&gt; per candidate), but the principle is the same: validate once, keep the handle, refuse a reparse change observed after open. The PR that landed the fix also added a unit test that creates a reparse point mid-traversal under a debugger breakpoint and asserts the scan refuses to descend. That is the kind of test that earns its place by reproducing the failure it is supposed to prevent.&lt;/p&gt;

&lt;h2&gt;
  
  
  The non-reparse offline file (the stale classifier, gate 3 by association)
&lt;/h2&gt;

&lt;p&gt;The third finding is closer to a stale classifier than a security boundary failure, but it is still P1 because the classifier decides what downstream code does with the result. &lt;code&gt;prototypes/blue-windows/cloudstate/observe_windows.go:41-42&lt;/code&gt; returns &lt;code&gt;StateLocal&lt;/code&gt; whenever &lt;code&gt;FILE_ATTRIBUTE_REPARSE_POINT&lt;/code&gt; is absent. The &lt;code&gt;OFFLINE&lt;/code&gt;, &lt;code&gt;RECALL_ON_OPEN&lt;/code&gt;, and &lt;code&gt;RECALL_ON_DATA_ACCESS&lt;/code&gt; flags are examined later in &lt;code&gt;classifyWindowsState&lt;/code&gt; at lines 73-74, which is unreachable for non-reparse files. A OneDrive file in the demoted state, a storage-tier-pinned file, or anything else marked offline without a reparse point will register as local. That is wrong, and the cost is that downstream criticality capture will under-count those files as low-risk.&lt;/p&gt;

&lt;p&gt;The fix is to evaluate the offline/recall mask before the non-reparse &lt;code&gt;StateLocal&lt;/code&gt; return. A non-reparse file with &lt;code&gt;FILE_ATTRIBUTE_OFFLINE&lt;/code&gt; should classify as &lt;code&gt;CLOUD_ONLY&lt;/code&gt; (or &lt;code&gt;UNKNOWN/unavailable&lt;/code&gt; if we want to be conservative on recall flags we cannot yet test on every Windows SKU). The native probe needs a regression test for a non-reparse offline file. That is also shipping today.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not the obvious approach?
&lt;/h2&gt;

&lt;p&gt;The obvious approach for standard-user state observation is to shell out to &lt;code&gt;manage-bde -status&lt;/code&gt; and parse the text. That is what every PowerShell script in the wild does. It works on a privileged user. It fails open on a standard user: the binary runs, every operation returns "Access is denied," and the parser does not know that is "no data" rather than "BitLocker off." The classifier ends up reporting everything as off.&lt;/p&gt;

&lt;p&gt;The other obvious approach is to elevate. &lt;code&gt;manage-bde&lt;/code&gt; is the right tool for the privileged envelope. Elevation is not available here. DOC-075/A03 is explicit: the standard-user constraint is the envelope, not a temporary compromise. WMI stays out. COM stays out. The shape that fits inside the envelope is the bounded native provider, the observer contract, and the fixture-boundary authorization. They are less convenient than &lt;code&gt;manage-bde&lt;/code&gt;. They are what works inside the envelope.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adjacent finding on the NVMe health-log parser
&lt;/h2&gt;

&lt;p&gt;The audit surfaced a separate bug in the NVMe health-log parser. The parser used wrong offsets: bytes 160-175 instead of 176-191. &lt;code&gt;NVME_HEALTH_INFO_LOG&lt;/code&gt; places UnsafeShutdowns at 160-175 and MediaErrors at 176-191, and the parser was rejecting every byte from 216 onward (which is also where valid sensors 7 and 8 live). Fail-closed against false healthy in some cases but capable of false critical/unknown and missing the documented media-error blocker. Not a P1 for this epic, but it is the next bead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Also shipped
&lt;/h2&gt;

&lt;p&gt;Other repos did work today, briefly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;omarchy-plugins-bluegold-email-fix&lt;/strong&gt;: closed FAQ panels 35 and 36, the adversarial buyer FAQ set. Buyer FAQ 36 is the version that survives a buyer who has already read the documentation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;intent-solutions-landing-bluegold-faq&lt;/strong&gt;: shipped v3.2.0 with a mobile conversion baseline (PR #54). The site finally renders the conversion CTA cleanly on a 360-pixel viewport.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;intent-demos&lt;/strong&gt;: launched the proof-first demos catalog (fd6198e) and fixed site previews on touch screens (6dc710d).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;contributing-clanker&lt;/strong&gt;: closed regression-state isolation and review-synthetic-alert tolerance fixes (#78 and #79).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;jeremylongshore-dot-github&lt;/strong&gt;: bound VPS deploys to the caller revision (#5). Deploys now refuse to land if the action SHA does not match the commit being deployed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;omarchy-listening-post-entry&lt;/strong&gt;: recorded approvals and bound deploy revisions (#19), launched the Perception product foundation (#18).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;braves&lt;/strong&gt;: a beads sync remote update only.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of those are the day's center. The day's center is intent-blue-gold, the three gates, and the audit that caught two of them slipping before they shipped to production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related posts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="//{{&lt;%20ref%20"&gt;}}"&amp;gt;Auditing Written Claims Against Their Artifacts&lt;/a&gt;: the second-review pattern across two unrelated domains. Today's Codex audit instantiates it on the BitLocker surface.&lt;/li&gt;
&lt;li&gt;
&lt;a href="//{{&lt;%20ref%20"&gt;}}"&amp;gt;Sealing a 168-bead planning graph took three reviews and a seven-seat council&lt;/a&gt;: planning under multi-review pressure, the day before.&lt;/li&gt;
&lt;li&gt;
&lt;a href="//{{&lt;%20ref%20"&gt;}}"&amp;gt;Adversarial review before team rollout&lt;/a&gt;: the adversarial pattern that the Codex audit instantiates on this surface.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>windows</category>
      <category>security</category>
      <category>bitlocker</category>
      <category>go</category>
    </item>
    <item>
      <title>Perception Is On the Way, on Its Own Domain</title>
      <dc:creator>Jeremy Longshore</dc:creator>
      <pubDate>Sun, 13 Sep 2026 11:30:14 +0000</pubDate>
      <link>https://dev.to/jeremy_longshore/perception-is-on-the-way-on-its-own-domain-53g6</link>
      <guid>https://dev.to/jeremy_longshore/perception-is-on-the-way-on-its-own-domain-53g6</guid>
      <description>&lt;p&gt;The day's pattern is the redirection. One Omarchy entry repo launched Perception's&lt;br&gt;
web/API surface and shipped a customer preview page to &lt;code&gt;perception.intentsolutions.io&lt;/code&gt;,&lt;br&gt;
but the live deployment was a coming-soon page rather than the full paid product.&lt;br&gt;
The smaller deployment was what the day's infrastructure could close. The same&lt;br&gt;
shift showed up on a second repo, where a 1,262-line master blueprint commit and&lt;br&gt;
17 documents filed into a flat chronological index paired with a 15-child Beads&lt;br&gt;
decomposition that waits on itself by design. Two products, two repos, one shared&lt;br&gt;
shape: ship the version the constraints can actually carry, and name the gap that&lt;br&gt;
forced the smaller scope.&lt;/p&gt;

&lt;h2&gt;
  
  
  omarchy-listening-post-entry: Perception's web and API surface, then the customer preview
&lt;/h2&gt;

&lt;p&gt;The repo shipped Perception in two commits on 2026-09-11. The first commit&lt;br&gt;
(&lt;code&gt;12ba7df feat: establish Perception web and API product&lt;/code&gt;, 00:17 -0600) was&lt;br&gt;
46 files, 5,894 insertions: a new &lt;code&gt;web/&lt;/code&gt; Vite + React app, a new &lt;code&gt;api/&lt;/code&gt; Fastify&lt;br&gt;
service with Dockerfile, and a &lt;code&gt;packages/perception-contract/&lt;/code&gt; shared schema&lt;br&gt;
package that the web app and the API both depend on. The contract carries the&lt;br&gt;
Perception v1 snapshot schema, with &lt;code&gt;snapshot.id&lt;/code&gt;, &lt;code&gt;snapshot.staleAfter&lt;/code&gt;,&lt;br&gt;
&lt;code&gt;snapshot.account&lt;/code&gt;, &lt;code&gt;snapshot.topics&lt;/code&gt;, and a &lt;code&gt;snapshot.signals&lt;/code&gt; array typed&lt;br&gt;
to &lt;code&gt;lane&lt;/code&gt; ∈ &lt;code&gt;incident | release | pricing | engineering&lt;/code&gt;. The web app imports&lt;br&gt;
the types directly from &lt;code&gt;@listening-post/perception-contract&lt;/code&gt;; the API and the&lt;br&gt;
contract tests share the same module.&lt;/p&gt;

&lt;p&gt;The second commit (&lt;code&gt;d992ce5 feat: prepare Perception customer preview&lt;/code&gt;,&lt;br&gt;
17:15 -0600) was 102 files, 5,077 insertions and added the rest of the&lt;br&gt;
customer-facing surface: a &lt;code&gt;PublicExperience.tsx&lt;/code&gt; that owns the public marketing&lt;br&gt;
site, four policy pages (privacy, terms, acceptable-use, support), a passwordless&lt;br&gt;
auth flow with magic links via &lt;code&gt;consumeMagicLink&lt;/code&gt; and &lt;code&gt;requestMagicLink&lt;/code&gt;,&lt;br&gt;
account views, customer-journey tests, and a &lt;code&gt;mailer.ts&lt;/code&gt; plus &lt;code&gt;customer-messages.ts&lt;/code&gt;&lt;br&gt;
plus &lt;code&gt;entitlements.ts&lt;/code&gt; plus &lt;code&gt;billing-webhook.test.ts&lt;/code&gt; that gate access on Lemon&lt;br&gt;
Squeezy subscription state. The schema gained a stricter signals shape (the&lt;br&gt;
array now requires &lt;code&gt;id, title, url, source, lane, relevance, resolved, quiet,&lt;br&gt;
matchedTopicIds, publishedAt, read&lt;/code&gt; per item with &lt;code&gt;additionalProperties: false&lt;/code&gt;).&lt;br&gt;
The manifest was updated to point &lt;code&gt;perceptionEndpoint&lt;/code&gt; at&lt;br&gt;
&lt;code&gt;https://api.perception.intentsolutions.io&lt;/code&gt; and the web &lt;code&gt;public/CNAME&lt;/code&gt; file&lt;br&gt;
was written with &lt;code&gt;perception.intentsolutions.io&lt;/code&gt;. PRODUCT.md, DESIGN.md,&lt;br&gt;
VERIFICATION.md, SECURITY.md, and CHANGELOG.md were authored together.&lt;/p&gt;

&lt;p&gt;That is the day's product surface. The live deploy is where the day's&lt;br&gt;
reversal starts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the live deploy is a coming-soon page
&lt;/h2&gt;

&lt;p&gt;The original direction arrived as a single line near the end of the day's&lt;br&gt;
session: "merge the prs commit push etc deploy the website i meed it online&lt;br&gt;
i meed it online i give u commercial and legal approval." That authorization&lt;br&gt;
covered the full paid-product release: the API at &lt;code&gt;api.perception.intentsolutions.io&lt;/code&gt;,&lt;br&gt;
the web app, the Lemon Squeezy checkout flow, and the policy pages as binding&lt;br&gt;
production terms.&lt;/p&gt;

&lt;p&gt;The agent surfaced four gaps before changing live traffic. GitHub Pages was&lt;br&gt;
not enabled on the repo. The three &lt;code&gt;PERCEPTION_*&lt;/code&gt; repository variables were&lt;br&gt;
absent. The VPS deploy secrets were absent. The custom domains for both&lt;br&gt;
&lt;code&gt;perception.intentsolutions.io&lt;/code&gt; and &lt;code&gt;api.perception.intentsolutions.io&lt;/code&gt; were&lt;br&gt;
failing DNS resolution. PRODUCT.md was explicit that price, billing interval,&lt;br&gt;
refund window, legal operator, governing law, and final checkout URL were&lt;br&gt;
deployment-owned open decisions. The customer copy labelled itself "not yet&lt;br&gt;
production terms."&lt;/p&gt;

&lt;p&gt;The redirect that followed read, verbatim: "dude i just want perception.intentsolutions.io&lt;br&gt;
to work as a site people click to know its on the way i posted it in discord."&lt;br&gt;
That is the day's reversal. The full release was deferred, not failed: the&lt;br&gt;
agent was told the goal had shrunk to a single page that says the product is&lt;br&gt;
on its way and links to the GitHub repo.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub Pages → VPS at intent-solutions
&lt;/h2&gt;

&lt;p&gt;The smaller deployment still needed a live URL. The agent's first attempt was&lt;br&gt;
GitHub Pages: a &lt;code&gt;gh-pages&lt;/code&gt; branch with the standalone coming-soon HTML and a&lt;br&gt;
Porkbun CNAME at 300s TTL. Pages was configured with Actions as its source,&lt;br&gt;
&lt;code&gt;PERCEPTION_DEMO_MODE=true&lt;/code&gt; was the only repo variable set, and the&lt;br&gt;
checkout/API variables were deliberately left unset so the preview could not&lt;br&gt;
masquerade as a paid production launch. DNS propagated. Pages started serving&lt;br&gt;
the page over HTTP. The certificate did not arrive.&lt;/p&gt;

&lt;p&gt;After the certificate stall, the agent switched to the VPS path that was&lt;br&gt;
already under control. Caddy was healthy on the VPS, passwordless sudo was&lt;br&gt;
available, and the same static page was served from there. The first Caddy&lt;br&gt;
reload failed closed because the new access-log file did not yet exist with&lt;br&gt;
Caddy ownership. The reload was isolated and retried after creating only&lt;br&gt;
that log file with the service's established permissions. The second reload&lt;br&gt;
succeeded. Porkbun was then asked to move the &lt;code&gt;perception&lt;/code&gt; CNAME from GitHub&lt;br&gt;
Pages to the VPS A record, with an automatic rollback path armed during the&lt;br&gt;
cutover. Caddy issued the Let's Encrypt certificate on retry. The local DNS&lt;br&gt;
resolver on the workstation had a stale negative cache for the new A record,&lt;br&gt;
which the agent bypassed to confirm the public origin.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;perception.intentsolutions.io&lt;/code&gt; now serves the coming-soon page over HTTPS&lt;br&gt;
from the VPS. The full paid product remains local and un-pushed; the open&lt;br&gt;
beads for price, billing interval, refund window, legal operator, governing&lt;br&gt;
law, and final checkout URL still own those decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  intent-blue-gold: 17 Stage 0 documents plus an Epic 0 Beads decomposition
&lt;/h2&gt;

&lt;p&gt;The second repo's day was a documentation discipline pass plus a Beads&lt;br&gt;
decomposition. The first commit (&lt;code&gt;d9cd691 docs: replace product summary with&lt;br&gt;
canonical MVP execution blueprint&lt;/code&gt;) added 1,262 insertions across a single&lt;br&gt;
file, the master blueprint that owns the BLUE → GOLD → BLUE → WELCOME&lt;br&gt;
sequence. The second commit (&lt;code&gt;a23517b docs: file Stage 0 repository records&lt;/code&gt;)&lt;br&gt;
filed 17 source documents (&lt;code&gt;PRODUCT.md&lt;/code&gt;, &lt;code&gt;V1-SCOPE.md&lt;/code&gt;, &lt;code&gt;RISK-REGISTER.md&lt;/code&gt;,&lt;br&gt;
&lt;code&gt;THREAT-MODEL.md&lt;/code&gt;, &lt;code&gt;MIGRATION-CONTRACT.md&lt;/code&gt;, &lt;code&gt;COMPATIBILITY.md&lt;/code&gt;, &lt;code&gt;RESEARCH.md&lt;/code&gt;,&lt;br&gt;
&lt;code&gt;AI-STRATEGY.md&lt;/code&gt;, &lt;code&gt;DECISIONS.md&lt;/code&gt;, &lt;code&gt;MASTER-BLUEPRINT.md&lt;/code&gt;, the &lt;code&gt;docs/&lt;/code&gt; subfolder&lt;br&gt;
documents) into a flat chronological &lt;code&gt;000-docs/&lt;/code&gt; tree using a global sequence&lt;br&gt;
plus an &lt;code&gt;AGENTS.md&lt;/code&gt; at root, a &lt;code&gt;CODEX-HANDOFF.md&lt;/code&gt; update, and a&lt;br&gt;
&lt;code&gt;000-docs/000-INDEX.md&lt;/code&gt; that names the order.&lt;/p&gt;

&lt;p&gt;The Beads side was harder. The first Beads init auto-adopted the unrelated&lt;br&gt;
Intent Eval Dolt database (1,499 imported issues inherited from a remote the&lt;br&gt;
agent had not selected). The first reset attempt succeeded technically but the&lt;br&gt;
inherited graph was still present in the local Dolt history. The second reset&lt;br&gt;
moved the &lt;code&gt;.beads/&lt;/code&gt; directory to &lt;code&gt;/tmp/intent-blue-gold-beads-XQ7n2p/imported-beads&lt;/code&gt;&lt;br&gt;
and &lt;code&gt;/tmp/intent-blue-gold-beads-reset-xXV59D/imported-beads&lt;/code&gt; and started&lt;br&gt;
with &lt;code&gt;dolt.local-only: true&lt;/code&gt; and &lt;code&gt;backup.enabled: false&lt;/code&gt; so no remote could be&lt;br&gt;
adopted. The third init came up clean (zero issues, no Dolt remote, no&lt;br&gt;
Intent Eval reference).&lt;/p&gt;

&lt;p&gt;On the clean workspace the master blueprint was decomposed into five epics,&lt;br&gt;
and Epic 0 (engineering foundation, CI/CD, repository quality gates) was&lt;br&gt;
decomposed into 15 bounded Beads children using three Luna-high subagents.&lt;br&gt;
The decomposition surfaced a cross-slice overlap (the CI orchestration bead&lt;br&gt;
and the bootstrap bead both claimed the local command), which was narrowed so&lt;br&gt;
CI consumes the bootstrap-owned gate rather than reimplementing it. The&lt;br&gt;
final DAG has nine dependency waves with maximum parallelism of three, a&lt;br&gt;
single onboarding/exit gate at the apex, and selective Epic 1 integration:&lt;br&gt;
research and safety-analysis work remains runnable, schema/fixture hardening&lt;br&gt;
waits for Epic 0 validators, experiment operationalization waits for workflow&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;destructive-test-isolation controls, and the controlled BLUE → GOLD → BLUE
proof waits for the final Epic 0 exit gate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Beads config (&lt;code&gt;dolt.local-only: true&lt;/code&gt;, &lt;code&gt;backup.enabled: false&lt;/code&gt;, no remote)&lt;br&gt;
was committed, the issue graph was validated with &lt;code&gt;bd lint&lt;/code&gt; and &lt;code&gt;bd dep cycles&lt;/code&gt;&lt;br&gt;
(zero cycles, zero lint warnings), and the worktree was committed, pushed,&lt;br&gt;
and merged to &lt;code&gt;main&lt;/code&gt; as PR #1 with &lt;code&gt;delete_branch_on_merge&lt;/code&gt; flipped from&lt;br&gt;
&lt;code&gt;false&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt; first via the GitHub repository API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Also shipped
&lt;/h2&gt;

&lt;p&gt;The comehomealabama journal (a separate Astro surface, not startaitools)&lt;br&gt;
published &lt;code&gt;ac9b179 post(journal): Orange Beach is three different decisions.&lt;br&gt;
Know which one you're making.&lt;/code&gt;, automated by &lt;code&gt;scripts/journal/mandy-land.sh&lt;/code&gt;&lt;br&gt;
after the voice and fair-housing lints both passed. That post lives on the&lt;br&gt;
Mandy machine and does not enter the startaitools archive.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it cost
&lt;/h2&gt;

&lt;p&gt;Two redirects, one certificate stall, one Caddy fail-closed reload, two&lt;br&gt;
failed Beads resets, and a 1,262-insertion master blueprint rewrite that&lt;br&gt;
became the canonical reference. The Perception web/API surface and the&lt;br&gt;
Beads Epic 0 graph both landed in their final form on the first attempt&lt;br&gt;
inside their own repositories. The deploy paths and the Beads remote selection&lt;br&gt;
each needed a second try. The customer-facing launch is now bounded by what&lt;br&gt;
HTTPS, Porkbun, and a Caddy file permission can carry, not by what the&lt;br&gt;
product itself can carry.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Posts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://startaitools.com/posts/the-same-mission-on-two-surfaces-in-one-day/" rel="noopener noreferrer"&gt;The Same Mission on Two Surfaces in One Day&lt;/a&gt;, 2026-09-10's pair of initial scaffolds and the marketplace claim ledger pattern that precedes the Perception customer preview&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://startaitools.com/posts/a-953-line-skill-entry-fits-the-budget-again/" rel="noopener noreferrer"&gt;A 953-Line Skill Entry Fits the Budget Again&lt;/a&gt;, 2026-09-09's split-and-pull-only refactor and the same-day 17-repo audit-harness refresh&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://startaitools.com/posts/hardening-a-marketplace-in-one-day/" rel="noopener noreferrer"&gt;Hardening a Marketplace in One Day&lt;/a&gt;, 2026-09-08's C44 installable-tree gate and the portable install integrity contract that ship next to the contributor workflow&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>omarchy</category>
      <category>releaseengineering</category>
      <category>deployment</category>
      <category>beads</category>
    </item>
    <item>
      <title>The Primary Record Settles What a Derived One Assumed</title>
      <dc:creator>Jeremy Longshore</dc:creator>
      <pubDate>Tue, 08 Sep 2026 11:30:14 +0000</pubDate>
      <link>https://dev.to/jeremy_longshore/the-primary-record-settles-what-a-derived-one-assumed-7oc</link>
      <guid>https://dev.to/jeremy_longshore/the-primary-record-settles-what-a-derived-one-assumed-7oc</guid>
      <description>&lt;p&gt;A legal packet had already been corrected once. That is what made the day worth&lt;br&gt;
writing down. The name on the drafts was wrong, somebody caught it, somebody&lt;br&gt;
fixed it against the records we had, and the fixed version was still wrong. On&lt;br&gt;
2026-09-06 the same shape showed up three more times, on systems that share no&lt;br&gt;
code: a homepage publishing three different star counts, a ratified security&lt;br&gt;
record, and a migration linter that counted an index build inside a log&lt;br&gt;
message.&lt;/p&gt;

&lt;p&gt;The common mechanism is boring and it costs a lot. A derived record is any&lt;br&gt;
statement of fact produced from another statement of fact rather than from the&lt;br&gt;
thing itself. Repo files describing an entity. An audit summarizing a record. A&lt;br&gt;
grep counting SQL. Each one is cheap to read and confident by default, because&lt;br&gt;
a derived record carries no expiry on its source unless someone builds one in.&lt;br&gt;
Only a primary record settles it: the state filing, the GitHub API, the&lt;br&gt;
governing section, the parsed statement.&lt;/p&gt;
&lt;h2&gt;
  
  
  The correction that was itself derived
&lt;/h2&gt;

&lt;p&gt;The legal packet's entity name had been fixed once already, from repo records.&lt;br&gt;
Those repo records had normalized the name at some earlier point, so the&lt;br&gt;
correction inherited the normalization. Commit &lt;code&gt;da39e57b&lt;/code&gt; says it plainly:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;the audit had corrected the name once from repo records that had normalized&lt;br&gt;
it; the primary record produced 2026-09-06 shows both earlier forms were wrong&lt;br&gt;
and the state of formation was an assumption the drafts had baked into&lt;br&gt;
governing law and forum.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The Certificate of Formation and the IRS EIN record arrived and closed two&lt;br&gt;
standing assumptions as false. A-02, the name spelling: the registered entity is&lt;br&gt;
&lt;strong&gt;IntentSolutions.io LLC&lt;/strong&gt;. A-01, the state of formation: Delaware, file&lt;br&gt;
10329498, formed 2025-09-11, registered agent Harvard Business Services.&lt;/p&gt;

&lt;p&gt;The name was a find-and-replace. The state of formation cost more, because it&lt;br&gt;
had never been written down as a fact anywhere. It was an assumption, and it had&lt;br&gt;
already propagated into meaning, since the governing-law and forum clauses of&lt;br&gt;
the contract templates were built on top of it. A wrong string is a lint. A&lt;br&gt;
wrong premise underneath a clause is a different category of problem, and no&lt;br&gt;
amount of internal review would have surfaced it, because every document in the&lt;br&gt;
packet agreed with every other document in the packet.&lt;/p&gt;

&lt;p&gt;Enforcement shipped with the correction, and the shape of the enforcement&lt;br&gt;
matters more than the value it now accepts. The validator does not check that&lt;br&gt;
the entity string looks plausible. It rejects the two specific forms we now know&lt;br&gt;
are retired:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ci/validate-legal-packet.sh &lt;span class="nt"&gt;--selftest&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;selftest] accepts: IntentSolutions.io LLC ....................... ok
&lt;span class="o"&gt;[&lt;/span&gt;selftest] rejects: retired form A &lt;span class="o"&gt;(&lt;/span&gt;pre-normalization&lt;span class="o"&gt;)&lt;/span&gt; ........... ok
&lt;span class="o"&gt;[&lt;/span&gt;selftest] rejects: retired form B &lt;span class="o"&gt;(&lt;/span&gt;repo-normalized&lt;span class="o"&gt;)&lt;/span&gt; ............. ok
&lt;span class="o"&gt;[&lt;/span&gt;selftest] 3/3 passed

&lt;span class="nv"&gt;$ &lt;/span&gt;ci/validate-legal-packet.sh
entity string: IntentSolutions.io LLC &lt;span class="o"&gt;(&lt;/span&gt;43 files checked&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;exit &lt;/span&gt;0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The retired forms are not printed here for the same reason the selftest labels&lt;br&gt;
them A and B: repeating a wrong name in public copy is how it gets re-derived.&lt;br&gt;
Formation screenshots live outside the repo. The EIN, street address, and phone&lt;br&gt;
never enter it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Formation state and governing law are separate questions
&lt;/h2&gt;

&lt;p&gt;The obvious move, once the formation state lands, is to sweep governing law and&lt;br&gt;
forum to Delaware and be done. We did the opposite. Alabama law and Baldwin&lt;br&gt;
County stay in the drafts, flagged as open counsel question C-14.&lt;/p&gt;

&lt;p&gt;Formation state and choice of governing law are different questions that happen&lt;br&gt;
to share a word. The business operates in Alabama, the founder is in Alabama,&lt;br&gt;
and the restrictive-covenant analysis (the clause set that actually bites in a&lt;br&gt;
dispute) is an Alabama-law question. Switching the contracts to Delaware because&lt;br&gt;
the certificate says Delaware would be a second derived conclusion stacked on&lt;br&gt;
the first one, produced by exactly the reasoning that caused the original&lt;br&gt;
problem: an inference from a nearby fact, written down with the confidence of a&lt;br&gt;
finding.&lt;/p&gt;

&lt;p&gt;The correct output of a primary-record check is a smaller set of facts and a&lt;br&gt;
larger set of explicit questions. C-14 is a question with a name and an owner.&lt;br&gt;
It is unresolved, and it is no longer silently assumed, which is where it sat&lt;br&gt;
yesterday.&lt;/p&gt;
&lt;h2&gt;
  
  
  Three star counts, none of them from GitHub
&lt;/h2&gt;

&lt;p&gt;Track two is the company homepage. The 451-line audit of the live&lt;br&gt;
intentsolutions.io found it publishing three contradictory star counts for the&lt;br&gt;
same repository, two of them above the verified figure. None of the three was&lt;br&gt;
read from GitHub. Each was typed into a component from whatever earlier copy&lt;br&gt;
the author had in front of them, and each component agreed with itself, so&lt;br&gt;
&lt;a href="https://dev.to/blog/the-lane-that-reviewed-nothing/"&gt;every review the page had passed&lt;/a&gt; was&lt;br&gt;
a review of derived numbers against other derived numbers. The same audit found a hero leading with retired Google&lt;br&gt;
infrastructure, five service lines, a booking calendar, and a contact form&lt;br&gt;
posting to an unrouted path.&lt;/p&gt;

&lt;p&gt;PR #49 shipped v3.0.0 as the fix: a static Astro rebuild derived from a written&lt;br&gt;
gateway brief, with React and the animation libraries removed, and 17 routes,&lt;br&gt;
30 dead components, 12.5 MB of unreferenced media, and 20 runtime dependencies&lt;br&gt;
deleted. The part that answers the thesis is smaller than the rebuild. Every&lt;br&gt;
figure on the page rendered from &lt;code&gt;src/data/receipts.json&lt;/code&gt;, which&lt;br&gt;
&lt;code&gt;scripts/refresh-receipts.mjs&lt;/code&gt; writes from GitHub, tonsofskills.com, skills.sh,&lt;br&gt;
the Lab results page, and the field-notes RSS. Each value carries a&lt;br&gt;
&lt;code&gt;verified_at&lt;/code&gt;. CI refreshes the file before deploy and fails the build when a&lt;br&gt;
value goes stale:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MAX_AGE_DAYS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;receipts&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ageDays&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;verified_at&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;86400000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ageDays&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;MAX_AGE_DAYS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; verified_at is &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;ageDays&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;d old (max &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;MAX_AGE_DAYS&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A count with a &lt;code&gt;verified_at&lt;/code&gt; is still a derived record. The difference is that&lt;br&gt;
it now expires, and the build knows the expiry. A second gate,&lt;br&gt;
&lt;code&gt;scripts/check-copy.mjs&lt;/code&gt;, failed on retired strings, dollar figures, dashes, and&lt;br&gt;
hand-typed counts, so while it was live the old failure could not be typed back&lt;br&gt;
in.&lt;/p&gt;

&lt;p&gt;PR #51 reverted the whole rebuild the same day. The owner's call, verbatim:&lt;br&gt;
"roll back to original please." The zinc theme, the React islands, all 29&lt;br&gt;
routes, the media, the dependencies, and the pre-rebuild CLAUDE.md all came&lt;br&gt;
back, with one merge conflict in the auto-generated CHANGELOG. We took a clean&lt;br&gt;
revert over a partial keep so main matches the last known live state exactly; a&lt;br&gt;
partial keep produces a fourth thing that was never live and never reviewed as&lt;br&gt;
a whole. The audit doc stayed on main, because a revert only removes what the&lt;br&gt;
reverted PR added, and the audit was independently true.&lt;/p&gt;

&lt;p&gt;This instance is a variant of the other three, and it is worth saying so. The&lt;br&gt;
brief was executed faithfully. What the revert corrected was not a false fact&lt;br&gt;
but a direction, and the only primary record for the direction is the owner.&lt;br&gt;
The second attempt did not guess at copy again. It put the live page in front&lt;br&gt;
of eight independent reader seats in one Workflow, with a ninth seat for&lt;br&gt;
synthesis, and filed the result as a 455-line review. The verdict was 8 of 8&lt;br&gt;
that the page does not represent the vision and that the fix is mostly&lt;br&gt;
subtraction. The headline vote split 6 to 2, and the merged recommendation&lt;br&gt;
ships both lines, the majority as H1 and the challenger in the eyebrow slot,&lt;br&gt;
because a 6/2 split and an 8/0 agreement are different facts about the copy&lt;br&gt;
and a single recommendation erases the difference. The synthesis escalated two&lt;br&gt;
items to the owner instead of resolving them, one being that several seats had&lt;br&gt;
written founder-biography detail into public copy against a standing&lt;br&gt;
instruction. A panel of readers is another derived record. The escalation is&lt;br&gt;
the step that reached primary.&lt;/p&gt;
&lt;h2&gt;
  
  
  A ratified record whose "no bead owed" was false
&lt;/h2&gt;

&lt;p&gt;Track three ran on &lt;code&gt;intent-longbox&lt;/code&gt;. Seven PRs on multi-tenant isolation&lt;br&gt;
merged the same day (#95 through #101: compound tenant keys, row-level security&lt;br&gt;
as a contracting shape, a single identity door, store-domain claims, membership&lt;br&gt;
policies, self-service second factor, webhook replay defense), and records 060&lt;br&gt;
through 065 were ratified. The compound key from #95 carries its whole&lt;br&gt;
isolation argument in the three lines before the close:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;scan_result&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt;          &lt;span class="n"&gt;uuid&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;shop_id&lt;/span&gt;     &lt;span class="n"&gt;uuid&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;shop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="n"&gt;session_id&lt;/span&gt;  &lt;span class="n"&gt;uuid&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shop_id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="k"&gt;FOREIGN&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shop_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;scan_session&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shop_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;DELETE&lt;/span&gt; &lt;span class="k"&gt;CASCADE&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tenant travels in the composite key, so a foreign key check cannot resolve against&lt;br&gt;
another shop's row even when the application forgets its predicate.&lt;/p&gt;

&lt;p&gt;Then the gate audit read record 065 and found its ground false. The record&lt;br&gt;
claimed no follow-up work was owed. The remaining cross-tenant edges were not&lt;br&gt;
actually exempt under record 062 section 4, which is the section the claim&lt;br&gt;
leaned on. Two beads were filed as a result, E03-D37 and E03-D38. D37 then moved&lt;br&gt;
from P3 to P2 because two of the remaining single-column tenant edges were&lt;br&gt;
reproduced as exploitable on head: a device credential revocation planted across&lt;br&gt;
shops, and a global UNIQUE on credential retirement evaluated with row-level&lt;br&gt;
security off.&lt;/p&gt;

&lt;p&gt;A ratified record is a derived record. Record 062 section 4 sits closer to&lt;br&gt;
primary, and reading it directly is what broke the claim.&lt;/p&gt;
&lt;h2&gt;
  
  
  The linter that counted a sentence
&lt;/h2&gt;

&lt;p&gt;The best small instance of the day came from the Postgres migration lint written to&lt;br&gt;
enforce the 044 index-lock rule. That rule caps how many index builds a single&lt;br&gt;
migration may take a heavy lock for. The lint counted index builds with a text&lt;br&gt;
grep, which meant it counted this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- migration 039, inside a DO block
DO $$
BEGIN
  RAISE NOTICE 'rebuilding: CREATE INDEX on inventory_item may take minutes';
END $$;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A string literal inside a log message. The grep read it as a sixth index build&lt;br&gt;
and failed the migration. A count of SQL objects was being derived from prose&lt;br&gt;
about SQL objects, inside the same file.&lt;/p&gt;

&lt;p&gt;Invariant review caught it before the lint shipped, and the note went on the&lt;br&gt;
bead so the name-collision lint being added next would avoid inheriting the same&lt;br&gt;
false positive. That bead then absorbed a second rule: &lt;code&gt;DROP CONSTRAINT&lt;/code&gt; on a&lt;br&gt;
live table takes the same lock declaration the &lt;code&gt;CREATE INDEX&lt;/code&gt; rule already&lt;br&gt;
demands. Migration 039's eleven ACCESS EXCLUSIVE locks come from &lt;code&gt;DROP&lt;br&gt;
CONSTRAINT&lt;/code&gt;, and 044 section 9 never reached that statement.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it cost
&lt;/h2&gt;

&lt;p&gt;One failure that day was a different shape, a rule you can step around rather&lt;br&gt;
than a wrong fact, and it belongs in the record. One commit went in with&lt;br&gt;
&lt;code&gt;--no-verify&lt;/code&gt; after four attempts to get the pre-commit hook's unit chain to&lt;br&gt;
finish under a load average above 40. The change was &lt;code&gt;.beads/issues.jsonl&lt;/code&gt;&lt;br&gt;
only, which no pre-commit stage tests, so the risk on that commit was near&lt;br&gt;
zero. The hole in the discipline is real anyway. A gate you can step around&lt;br&gt;
under load will be stepped around again, and the honest fix is making the hook&lt;br&gt;
cheap enough to always run.&lt;/p&gt;

&lt;p&gt;The day ran 6 project-days across 21.75 hours of wall span, with 25&lt;br&gt;
failure-to-fix moments and 7 course-corrections in the session digest. The&lt;br&gt;
&lt;code&gt;intent-longbox&lt;/code&gt; chain ran on Claude Fable 5.1 across 9 sessions and 967&lt;br&gt;
minutes, with 48 agent dispatches and 35 resumes. That ratio describes the work&lt;br&gt;
better than the turn count does: most of it was dispatching a reviewer and&lt;br&gt;
later resuming it for a verdict. The gate audit that refuted record 065 is one&lt;br&gt;
of those 48. The &lt;code&gt;claude-code-plugins&lt;/code&gt; thread ran on GPT-5.6 Sol via Codex, and&lt;br&gt;
every one of its five course-corrections was a containment instruction ("read&lt;br&gt;
only: do not edit, push, comment, merge, close") or a demand for a verdict from&lt;br&gt;
evidence already gathered. None corrected a wrong answer. The legal thread ran&lt;br&gt;
on Claude Fable 5.1 across 6 sessions and 1306 minutes, and included one agent&lt;br&gt;
run interrupted mid-flight because I was messaging counsel on LinkedIn in real&lt;br&gt;
time and needed a specific message sent right then.&lt;/p&gt;

&lt;h2&gt;
  
  
  Change what the checker keys on
&lt;/h2&gt;

&lt;p&gt;When a checker is wrong, fixing the value is half the job. Change what the&lt;br&gt;
checker keys on.&lt;/p&gt;

&lt;p&gt;The legal validator stopped accepting whatever string the repo files agreed on&lt;br&gt;
and started rejecting two named retired forms. The receipts gate stopped&lt;br&gt;
trusting a committed number and started failing on &lt;code&gt;verified_at&lt;/code&gt; age; it went&lt;br&gt;
out with the revert and is the first thing the second attempt brings back. The&lt;br&gt;
migration lint is being moved off text grep onto parsed statements; that one is&lt;br&gt;
filed on a bead, not shipped. And the site copy stopped being resolved inside&lt;br&gt;
the panel and started being escalated to the owner, with the dissent preserved&lt;br&gt;
on the way up.&lt;/p&gt;

&lt;p&gt;Every one of those is the same move: take the authority away from the derived&lt;br&gt;
artifact and give it to something closer to the thing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Also shipped
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;intent-os document filing.&lt;/strong&gt; &lt;code&gt;business-plan/gateway/&lt;/code&gt; moved into
&lt;code&gt;000-docs/163-PP-gateway-vision/&lt;/code&gt; (files 164 to 171) and &lt;code&gt;legal/&lt;/code&gt; into
&lt;code&gt;000-docs/172-BL-legal-packet/&lt;/code&gt; (files 173 to 214). Two clusters instead of
one nested folder, because the standard forbids folders within folders. Every
cross-reference, lint ignore, repo index, CLAUDE.md, README, and
partner-network cockpit pointer was repointed, and source-form sha256 values
were verified identical before and after the rename before regenerating the
manifest. The validator got the same treatment as everything above: re-rooted
at the cluster and keyed by category codes instead of positional filenames,
since file position is a derived property that any rename breaks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Five Reddit introduction posts&lt;/strong&gt; for r/ClaudeAI, r/SideProject,
r/vibecoding, r/startups, and r/Entrepreneur, value-first, with posting rules
(one account, home connection, comment before posting, and links omitted where
the sub forbids them). Five distinct story posts rather than one generic post
copied five times, because identical cross-posting is what gets flagged.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Legal drafts alongside the entity correction:&lt;/strong&gt; a two-member member-managed
Delaware operating agreement, a customer-facing security statement claiming no
certifications because we hold none, and a beads epic (&lt;code&gt;spine-0ce&lt;/code&gt;) with seven
children, one per purchase, filing, or decision only the owner can execute.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;omarchy-omatrail-entry&lt;/strong&gt;, a frontier survival game in QML and JavaScript,
over 3,000 lines of rules and views, plus &lt;code&gt;bin/omatrail-state&lt;/code&gt;, an
end-to-end harness with save fixtures, and an &lt;code&gt;evidence/render-matrix&lt;/code&gt;
carrying per-scene PNGs next to render-proof JSON. A nine-document design
workbook landed alongside it in omarchy.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why does a text grep fail at counting SQL objects?
&lt;/h3&gt;

&lt;p&gt;A grep counts text, not statements. The Postgres migration lint on 2026-09-06&lt;br&gt;
searched for CREATE INDEX and matched a RAISE NOTICE message that described an&lt;br&gt;
index build in prose. It counted that sentence as a sixth index build and&lt;br&gt;
failed the migration. The fix that is filed, and not yet shipped, is to parse&lt;br&gt;
the statements instead of searching for words about them.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the difference between a primary record and a derived record?
&lt;/h3&gt;

&lt;p&gt;A primary record is the thing itself: the state filing, the GitHub API, the&lt;br&gt;
governing section of a ratified record, the parsed SQL statement. A derived&lt;br&gt;
record is any statement of fact produced from another statement of fact rather&lt;br&gt;
than from the thing. Repo files describing an entity, an audit summarizing a&lt;br&gt;
record, a grep counting SQL. A derived record carries no expiry on its source&lt;br&gt;
unless someone builds one in.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I stop a checker from re-deriving the same wrong answer?
&lt;/h3&gt;

&lt;p&gt;Change what the checker keys on. The legal validator stopped accepting whatever&lt;br&gt;
string the repo files agreed on and started rejecting two named retired forms.&lt;br&gt;
The receipts gate keyed on &lt;code&gt;verified_at&lt;/code&gt; age instead of a committed number&lt;br&gt;
while it was live, and it comes back with the second attempt. The migration&lt;br&gt;
lint is being moved from text grep to parsed statements. Each move takes&lt;br&gt;
authority away from the derived artifact and gives it to something closer to&lt;br&gt;
the thing.&lt;/p&gt;

&lt;p&gt;{&lt;br&gt;
  "&lt;a class="mentioned-user" href="https://dev.to/context"&gt;@context&lt;/a&gt;": "&lt;a href="https://schema.org" rel="noopener noreferrer"&gt;https://schema.org&lt;/a&gt;",&lt;br&gt;
  "@type": "FAQPage",&lt;br&gt;
  "mainEntity": [&lt;br&gt;
    {&lt;br&gt;
      "@type": "Question",&lt;br&gt;
      "name": "Why does a text grep fail at counting SQL objects?",&lt;br&gt;
      "acceptedAnswer": {&lt;br&gt;
        "@type": "Answer",&lt;br&gt;
        "text": "A grep counts text, not statements. The Postgres migration lint on 2026-09-06 searched for CREATE INDEX and matched a RAISE NOTICE message that described an index build in prose. It counted that sentence as a sixth index build and failed the migration. The fix that is filed, and not yet shipped, is to parse the statements instead of searching for words about them."&lt;br&gt;
      }&lt;br&gt;
    },&lt;br&gt;
    {&lt;br&gt;
      "@type": "Question",&lt;br&gt;
      "name": "What is the difference between a primary record and a derived record?",&lt;br&gt;
      "acceptedAnswer": {&lt;br&gt;
        "@type": "Answer",&lt;br&gt;
        "text": "A primary record is the thing itself: the state filing, the GitHub API, the governing section of a ratified record, the parsed SQL statement. A derived record is any statement of fact produced from another statement of fact rather than from the thing. Repo files describing an entity, an audit summarizing a record, a grep counting SQL. A derived record carries no expiry on its source unless someone builds one in."&lt;br&gt;
      }&lt;br&gt;
    },&lt;br&gt;
    {&lt;br&gt;
      "@type": "Question",&lt;br&gt;
      "name": "How do I stop a checker from re-deriving the same wrong answer?",&lt;br&gt;
      "acceptedAnswer": {&lt;br&gt;
        "@type": "Answer",&lt;br&gt;
        "text": "Change what the checker keys on. The legal validator stopped accepting whatever string the repo files agreed on and started rejecting two named retired forms. The receipts gate keyed on verified_at age instead of a committed number while it was live, and it comes back with the second attempt. The migration lint is being moved from text grep to parsed statements. Each move takes authority away from the derived artifact and gives it to something closer to the thing."&lt;br&gt;
      }&lt;br&gt;
    }&lt;br&gt;
  ]&lt;br&gt;
}&lt;/p&gt;

&lt;h2&gt;
  
  
  Related posts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/blog/the-second-review-that-audits-the-claims/"&gt;Auditing Written Claims Against Their Artifacts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/blog/we-told-the-auditors-to-refute-us/"&gt;A Closed Epic Is a Claim, Not a Fact&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://startaitools.com/posts/stop-trusting-the-stored-claim/" rel="noopener noreferrer"&gt;When a Gate Should Re-Run the Step Instead of Trusting Its Receipt&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>architecture</category>
      <category>governance</category>
      <category>postgres</category>
      <category>dataintegrity</category>
    </item>
    <item>
      <title>Auditing Written Claims Against Their Artifacts</title>
      <dc:creator>Jeremy Longshore</dc:creator>
      <pubDate>Mon, 07 Sep 2026 11:30:11 +0000</pubDate>
      <link>https://dev.to/jeremy_longshore/auditing-written-claims-against-their-artifacts-3k9n</link>
      <guid>https://dev.to/jeremy_longshore/auditing-written-claims-against-their-artifacts-3k9n</guid>
      <description>&lt;p&gt;Code review asks whether the decision was correct. It almost never asks whether&lt;br&gt;
the paragraph describing the decision is accurate. On 2026-09-05 I watched that&lt;br&gt;
gap open in two places with nothing in common, neither language nor reviewer: a&lt;br&gt;
multi-tenant SaaS built under a heavy evidence discipline, and a stack of&lt;br&gt;
contract drafts with no software in them at all. The two records had reached&lt;br&gt;
different stages. The &lt;code&gt;intent-longbox&lt;/code&gt; records had been through a dispatched review and&lt;br&gt;
in some cases a ratification. The legal packet had passed only its author, who&lt;br&gt;
committed it as a finished deliverable with &lt;code&gt;[COUNSEL:]&lt;/code&gt; markers still in the&lt;br&gt;
text. Both were carrying claims that were false.&lt;/p&gt;

&lt;p&gt;Roughly twenty statements of fact got repaired across that one day. Nine in one&lt;br&gt;
commit, eight in another, one security claim withdrawn after a reviewer measured&lt;br&gt;
it false, and one use of the word "proved" downgraded to the rung its evidence&lt;br&gt;
actually reached. The count runs per false claim rather than per place it was&lt;br&gt;
written, so the withdrawn security claim counts once even though several sites in&lt;br&gt;
the record carried it, and the downgrade counts once across two register rows. Every one of those records had already been read by a&lt;br&gt;
reviewer, and in two cases had already been ratified.&lt;/p&gt;

&lt;p&gt;The thesis I came out with: a review that only checks decisions leaves the&lt;br&gt;
prose ungated, and the prose is what everyone downstream cites.&lt;/p&gt;
&lt;h2&gt;
  
  
  Two review lanes, and only one of them reads sentences
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;intent-longbox&lt;/code&gt; repo runs work through what I call the two-lens cannon. Two&lt;br&gt;
named reviewer agents take a change from different value systems, currently&lt;br&gt;
&lt;code&gt;security-auditor&lt;/code&gt; and &lt;code&gt;martin-kleppmann-reviewer&lt;/code&gt;, and each returns a verdict.&lt;br&gt;
Alongside them sit two narrower jobs: a gate auditor, whose mandate is the&lt;br&gt;
record rather than the code, and an invariant reviewer, which checks that the&lt;br&gt;
system's stated invariants still hold. On some changes a MiniMax adversarial&lt;br&gt;
review runs on top of that.&lt;/p&gt;

&lt;p&gt;The day's volume was real. On main, 2026-09-05 changed 191 files, 42,385 lines&lt;br&gt;
added and 1,433 deleted, across 33 commits and seven merged pull requests (#88&lt;br&gt;
to #94). The features were substantial on&lt;br&gt;
their own. The seven merged that day:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;PR&lt;/th&gt;
&lt;th&gt;Diff&lt;/th&gt;
&lt;th&gt;What landed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;#90&lt;/td&gt;
&lt;td&gt;+11645/-865&lt;/td&gt;
&lt;td&gt;PostgreSQL row-level security with transaction-local tenant context, plus property tests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;#94&lt;/td&gt;
&lt;td&gt;+9916/-330&lt;/td&gt;
&lt;td&gt;The first factor and the privileged-session shape&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;#92&lt;/td&gt;
&lt;td&gt;+8981/-81&lt;/td&gt;
&lt;td&gt;A Longbox-origin predicate so a staff session outside a break-glass grant is visible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;#88&lt;/td&gt;
&lt;td&gt;+9557/-86&lt;/td&gt;
&lt;td&gt;Least-privilege organization and location RBAC, trustworthy actor audit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;#93&lt;/td&gt;
&lt;td&gt;+663/-23&lt;/td&gt;
&lt;td&gt;N:1 authorization decisions under an idempotent replay, refusing the dedup key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;#89&lt;/td&gt;
&lt;td&gt;+543/-158&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;noPropertyAccessFromIndexSignature&lt;/code&gt; turned on&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;#91&lt;/td&gt;
&lt;td&gt;+1223/-109&lt;/td&gt;
&lt;td&gt;The causal reference persisted on two tables&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two more pieces the day leaned on had merged the night before: TOTP and recovery&lt;br&gt;
codes for owner and support roles in #82, and connector OAuth with least scopes&lt;br&gt;
and uninstall revocation in #87.&lt;/p&gt;

&lt;p&gt;None of those features is the story. The story is the five commits that followed&lt;br&gt;
them, each one repairing a written record that the first review had already&lt;br&gt;
cleared.&lt;/p&gt;
&lt;h2&gt;
  
  
  Nine fact repairs from one gate audit
&lt;/h2&gt;

&lt;p&gt;Commit &lt;code&gt;2173407&lt;/code&gt; carries the plainest version of the split, and it took two&lt;br&gt;
lanes to get there. The gate auditor returned NOT-READY. Every decision item in&lt;br&gt;
the record passed. Six statements of fact did not. The invariant reviewer, run&lt;br&gt;
against the same head, returned PASS-WITH-NOTES and found three more.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gate audit verdict:        NOT-READY
  decision items:          all verified as recorded
  fact repairs:            6
  scope:                   paperwork only, no ruling moved

invariant re-verification: PASS-WITH-NOTES
  further fact repairs:    3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read that verdict twice. The engineering was right. The document describing the&lt;br&gt;
engineering could not be cited. The six repairs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A test file held 21 cases, and the record said 18. That pushed the bead's
unit total from 34 to 37, and two separate registers were carrying 34.&lt;/li&gt;
&lt;li&gt;Three beads described as "proposed, not yet created" already existed. The
session had filed them while the branch was in flight, so every "proposed"
hedge got replaced with a real id.&lt;/li&gt;
&lt;li&gt;A section asserted an act that had not happened. The phrase "is corrected
accordingly" was false at the moment someone typed it, because nothing had
done the correcting. It is true now by a different route, with the who and
the when named.&lt;/li&gt;
&lt;li&gt;A residual finding, R9, had no owning bead. A residual nobody owns is a
residual nobody reads twice.&lt;/li&gt;
&lt;li&gt;A citation of the three-layers quote pointed at &lt;code&gt;034:447&lt;/code&gt; when the quote sits
at &lt;code&gt;034:449&lt;/code&gt;. The repair also named &lt;code&gt;034:445-447&lt;/code&gt; separately, which is the
K1 trigger, a different quote entirely.&lt;/li&gt;
&lt;li&gt;A register cell claimed a status its evidence did not support, reading
VERIFIED by execution across both halves when only the refusing half had
been run.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;citation repair, three-layers quote
  before: 034:447
  after:  034:449

cited separately by the same repair
  034:445-447   (the K1 trigger)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That fifth one looks like a typo and is not. A line-number citation is a promise&lt;br&gt;
that a reader who follows it lands on the sentence being quoted. Land two lines&lt;br&gt;
short and the reader meets a different claim, then either loses trust in the&lt;br&gt;
record or keeps reading and inherits the wrong quote. The commit describes the&lt;br&gt;
gap as one line; the diff shows two. I have left both readings visible rather&lt;br&gt;
than picking the tidier one.&lt;/p&gt;
&lt;h3&gt;
  
  
  The three the invariant lane found
&lt;/h3&gt;

&lt;p&gt;The gate auditor reads the record against its own citations. The invariant&lt;br&gt;
reviewer reads the record against the running system, which is why the three it&lt;br&gt;
turned up are heavier.&lt;/p&gt;

&lt;p&gt;Section 6.3 of the record claimed there was nothing to repair. That was false by&lt;br&gt;
exactly one. A UNIQUE index on &lt;code&gt;shop.shopify_domain&lt;/code&gt;, added by migration 026 back&lt;br&gt;
when &lt;code&gt;shop&lt;/code&gt; carried no policy, is precisely the shape section 6.3 warns about,&lt;br&gt;
and the bead inherited it the moment it policied &lt;code&gt;shop&lt;/code&gt;. Reproduced under shop&lt;br&gt;
B's tenant context, claiming a domain that shop A already holds returns 23505,&lt;br&gt;
and claiming an unused one returns UPDATE 1. Two different answers, decided by a&lt;br&gt;
row the caller is not allowed to see. That is a one-bit oracle on which Shopify&lt;br&gt;
stores are Longbox customers. It is latent today because no route writes&lt;br&gt;
&lt;code&gt;shopify_domain&lt;/code&gt;, and latent is a schedule rather than a verdict. Section 6.3 now&lt;br&gt;
names it and routes it to an existing bead's class instead of inventing a new&lt;br&gt;
rule for it.&lt;/p&gt;

&lt;p&gt;The second was a new residual, R10. The domain-claim check in &lt;code&gt;receiveCallback&lt;/code&gt;&lt;br&gt;
has a TOCTOU window: the SELECT runs in one scope and the write runs in a&lt;br&gt;
separate transaction under the shop's tenant context, so two concurrent installs&lt;br&gt;
of the same store can both pass the check. The commit named the window and took&lt;br&gt;
neither of the two obvious fixes. Moving the check inside the transaction puts&lt;br&gt;
it under a tenant context where other shops' rows are invisible, so it would&lt;br&gt;
fail open, which is worse than the bug. Running the whole install in the service&lt;br&gt;
scope needs exactly the policy widening the security lens had just punished. The&lt;br&gt;
durable fix is the serialization point the database already owns, which is the&lt;br&gt;
unique index above, so the residual sits and waits for the bead that covers it.&lt;/p&gt;

&lt;p&gt;The third repair is the one I would put in front of anyone who thinks this lane&lt;br&gt;
is pedantry. A register cell's reproduction command named a GUC that does not&lt;br&gt;
exist. &lt;code&gt;longbox.service_scope&lt;/code&gt; names the SQL function, while the setting itself is&lt;br&gt;
called &lt;code&gt;longbox.service&lt;/code&gt;. Run verbatim, the cell returned zero rows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;current_setting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'longbox.service_scope'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;rows&lt;/span&gt;
&lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="nb"&gt;real&lt;/span&gt; &lt;span class="n"&gt;GUC&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="n"&gt;current_setting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'longbox.service'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The commit called it the worst kind of evidence, because it looks checkable and&lt;br&gt;
appears to disprove the claim it supports. A reader who runs it sees an empty&lt;br&gt;
result and concludes the invariant is broken. A reader who does not run it&lt;br&gt;
carries a citation that has never worked. The cell now reproduces standalone.&lt;/p&gt;

&lt;p&gt;Six plus three is the nine. The commit message carries a line I have kept: a&lt;br&gt;
record whose decisions are right and whose facts are wrong is still a record&lt;br&gt;
that cannot be cited. The same shape showed up earlier this year in &lt;a href="https://startaitools.com/posts/a-green-result-only-covers-what-it-ran/" rel="noopener noreferrer"&gt;Every Verdict Carries the Scope It Actually Ran&lt;/a&gt;, where a green result was reporting on less than it claimed.&lt;/p&gt;
&lt;h2&gt;
  
  
  Eight statements, and two ratified records a rebase damaged
&lt;/h2&gt;

&lt;p&gt;Commit &lt;code&gt;af3aa84&lt;/code&gt; came out of the next gate re-audit. Same shape of verdict:&lt;br&gt;
NOT-READY on paperwork only, every ruling verified as recorded and built,&lt;br&gt;
nothing moved a decision. Eight repairs this time, and two of them were damage&lt;br&gt;
rather than drift.&lt;/p&gt;

&lt;p&gt;The first piece of damage was in an append log. A rebase reconciliation filter&lt;br&gt;
had silently dropped a ratified entry belonging to a different branch, because&lt;br&gt;
that row's own text happened to mention the current branch's bead id. The filter&lt;br&gt;
matched on a substring and took a stranger's row with it. An append log that&lt;br&gt;
loses an entry has stopped being an append log.&lt;/p&gt;

&lt;p&gt;The repair restored the row verbatim from &lt;code&gt;origin/main&lt;/code&gt; and showed the&lt;br&gt;
restoration accounted for by a set diff rather than by an eyeball:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git show origin/main:000-docs/016-OD-REGS-longbox-source-register.md &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/main-appends
&lt;span class="c"&gt;# extract entry ids from both sides, compare as sets&lt;/span&gt;
&lt;span class="c"&gt;# result: all 32 of main's appends present and accounted for on the branch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restoring the text is the easy half. Showing that nothing else went missing in&lt;br&gt;
the same filter pass is the half that makes the record citable again, and a set&lt;br&gt;
diff is the cheapest instrument that does it.&lt;/p&gt;

&lt;p&gt;The second piece of damage was subtler. A ratified record's table cell had been&lt;br&gt;
edited in place instead of appended to. The amendment was correct. Its form was&lt;br&gt;
illegal. In a record with a version and a ratification date, an in-place edit&lt;br&gt;
rewrites what a reader who cited the earlier version thought they were citing.&lt;br&gt;
The repair restored main's sentence verbatim and appended the new pin after it.&lt;br&gt;
The record's version number did not move, because the amendment is the same&lt;br&gt;
amendment; only its shape changed.&lt;/p&gt;

&lt;p&gt;Six of the other repairs in that commit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A heading cited a stale commit while the section above it had already been
corrected to a newer one.&lt;/li&gt;
&lt;li&gt;A section called a commit "the main this branch is rebased onto" when it was
the merge base, and main was a different commit.&lt;/li&gt;
&lt;li&gt;Two sections routed a decision row to a bead as OPEN when the bead was CLOSED.
The fix restated it as a closed ruling rather than deleting the row, so a
reader who met the property in the earlier version is not left hunting a fix
that is never coming.&lt;/li&gt;
&lt;li&gt;A claim of "all twelve invariants proved against a database" was really eleven
of fourteen. The record had counted twelve invariants; the real total is
fourteen, of which eleven carry database evidence. One of the remaining three
is an architecture gate and two are unit-level, so the word "all" was claiming
database evidence that three invariants do not have.&lt;/li&gt;
&lt;li&gt;"Gains five cases" was seven.&lt;/li&gt;
&lt;li&gt;Every duration quoted as a measured property (24 hours, 15 minutes, 30 days)
was relabeled a provisional constant.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last one is the one I would defend hardest. The real argument in that&lt;br&gt;
section is that each act outlives the session that created it, and that argument&lt;br&gt;
holds whatever the constants are. Quoting the numbers as durations stated a&lt;br&gt;
property nobody had measured, and it invited a future reader to treat a config&lt;br&gt;
value as a finding.&lt;/p&gt;
&lt;h2&gt;
  
  
  The claim a reviewer measured false
&lt;/h2&gt;

&lt;p&gt;Commit &lt;code&gt;177cd3d&lt;/code&gt; is the centerpiece, because a reviewer did not argue about&lt;br&gt;
wording. It ran the thing.&lt;/p&gt;

&lt;p&gt;The record claimed that a tighter per-identifier sign-in rate bucket "closes" a&lt;br&gt;
user-enumeration timing oracle, and that a known address and an unknown address&lt;br&gt;
"start refusing fast at the same attempt count". The reviewer measured minute&lt;br&gt;
two, the first minute after the bucket refills, which is exactly when a warmed&lt;br&gt;
known address falls out of it. The result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;warmed KNOWN address:     6 to 16 ms on 4 of 5 attempts
UNKNOWN address:          about 600 ms on 5 of 5 attempts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An attacker with a stopwatch can read that difference through any amount of&lt;br&gt;
network jitter. The claim was false.&lt;/p&gt;

&lt;p&gt;The root cause was a window mismatch nobody had costed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;per-identifier sign-in rate bucket:  refills every 1 minute
LOCKOUT_WINDOW_MS:                   15 minutes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A warmed known address drops out of the one-minute bucket and falls back onto&lt;br&gt;
its fifteen-minute lockout path roughly fourteen times an hour, and every time&lt;br&gt;
it does, it answers cheap. What the tighter bucket actually bought was a rate&lt;br&gt;
cut on the oracle, from roughly 120 observations a minute down to roughly 5. A&lt;br&gt;
rate cut is a real security improvement. It is a different improvement from the&lt;br&gt;
one the record advertised.&lt;/p&gt;

&lt;p&gt;One section of that record, R10, had said this correctly the whole time:&lt;br&gt;
"narrows the window rather than closing the class". Six other sites in the&lt;br&gt;
record and the source contradicted it, or eight, depending on which part of the&lt;br&gt;
commit you read: it counts six and its own list names eight. All of them were&lt;br&gt;
corrected to match the one&lt;br&gt;
that was right, which is a satisfying shape for a repair: the truth was already&lt;br&gt;
in the building, outnumbered.&lt;/p&gt;
&lt;h3&gt;
  
  
  Adding nothing was the right call
&lt;/h3&gt;

&lt;p&gt;No fix shipped with that correction, and the decision was deliberate.&lt;/p&gt;

&lt;p&gt;Closing the class means hashing while blocked, so that a refused known address&lt;br&gt;
pays the same CPU as an unknown one. A ratified document in this system refuses&lt;br&gt;
that, and the bead doing the correction has no mandate to reopen it.&lt;/p&gt;

&lt;p&gt;The alternative that lost was widening the lockout window to match the bucket.&lt;br&gt;
That is a two-line change and it would have made the two paths agree. It also&lt;br&gt;
changes another ratified document's delay from inside a bead that never argued&lt;br&gt;
for touching it. Buying an accurate sentence by quietly editing somebody else's&lt;br&gt;
ratified constant is a worse trade than living with a narrowed residual.&lt;/p&gt;

&lt;p&gt;So what stands is a narrowed residual with its own row in the register. Someone&lt;br&gt;
will pick that row up with a mandate that covers it.&lt;/p&gt;

&lt;p&gt;There was a bookkeeping consequence too. Two claim ids, C47 and C48, collided:&lt;br&gt;
another bead's C47 and C48 had landed on main in parallel, so the register&lt;br&gt;
briefly carried four rows under two ids. The ratified ids kept their numbers,&lt;br&gt;
this branch's renumbered to C49 and C50, and the renumbering went into an append&lt;br&gt;
rather than happening quietly. A claim id that moves without a note is a&lt;br&gt;
citation nobody can follow backwards.&lt;/p&gt;
&lt;h2&gt;
  
  
  Downgrading "proved" to the rung the artifact reached
&lt;/h2&gt;

&lt;p&gt;Commit &lt;code&gt;2e7f3d2&lt;/code&gt; came from a MiniMax adversarial review that pressed on a single&lt;br&gt;
word in two register rows. It was written the night before and landed on main in&lt;br&gt;
the first hour of the 5th, through PR #89. Both rows said a compiler-flag-flip result was "proved able to fail",&lt;br&gt;
while linking only to CI runs where the flag was on.&lt;/p&gt;

&lt;p&gt;That is a structural argument that flipping the flag would produce the outcome.&lt;br&gt;
The record presented it as a recording of an actual flip. The governing rule in this repo is&lt;br&gt;
narrow and useful: a claim may not use a stronger rung than the artifact it&lt;br&gt;
cites.&lt;/p&gt;

&lt;p&gt;What the CI runs actually prove is that the flag is set in the repository's&lt;br&gt;
config, and that the dot access is what the compiler refuses, since a bracket&lt;br&gt;
twin compiles right beside it. They do not prove that the flag is the reason.&lt;br&gt;
Establishing that requires flipping it, which is a local reproduction, so it got&lt;br&gt;
recorded as one, with the command that produces it:&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;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'s/"noPropertyAccessFromIndexSignature": true/"noPropertyAccessFromIndexSignature": false/'&lt;/span&gt; tsconfig.json
pnpm vitest run tests/contract/signature-fields-are-not-dot-accessed.test.ts
&lt;span class="c"&gt;# 2 failed | 4 passed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I re-ran that at the commit rather than quoting the earlier session's output,&lt;br&gt;
which matters more than it sounds: a number copied forward from a previous&lt;br&gt;
session is a claim about a commit nobody checked. The two that fail are&lt;br&gt;
&lt;code&gt;is set in the repository's tsconfig&lt;/code&gt; (12 ms) and &lt;code&gt;refuses fields.series in&lt;br&gt;
src/services with TS4111&lt;/code&gt; (13.68 s). &lt;code&gt;tsconfig.json&lt;/code&gt; was restored afterwards,&lt;br&gt;
which is why it is absent from the diff.&lt;/p&gt;
&lt;h3&gt;
  
  
  The seventh CI case that lost
&lt;/h3&gt;

&lt;p&gt;The obvious response is to add a seventh CI case that does the flip&lt;br&gt;
automatically. I turned it down for three reasons, and the third one decided it.&lt;/p&gt;

&lt;p&gt;A CI version has to either mutate the repository's own &lt;code&gt;tsconfig.json&lt;/code&gt;, which is&lt;br&gt;
the same hazard another bead forbids one level up for &lt;code&gt;src/&lt;/code&gt;, and this time on&lt;br&gt;
the file every other test is judged by; or compile against a modified copy of&lt;br&gt;
the config, which is exactly what an existing case named &lt;code&gt;compiles the scratch&lt;br&gt;
tree against the repository's own tsconfig&lt;/code&gt; exists to rule out. Both options&lt;br&gt;
undo a guarantee that is already paid for.&lt;/p&gt;

&lt;p&gt;The third reason is cost. It would add a fourth &lt;code&gt;tsc&lt;/code&gt; spawn to a test file the&lt;br&gt;
same reviewer had already flagged as the second slowest in the unit lane. A&lt;br&gt;
written command a reader can re-run in thirty seconds beats a permanent tax on&lt;br&gt;
every run for the same evidence.&lt;/p&gt;
&lt;h3&gt;
  
  
  The reviewer got audited back
&lt;/h3&gt;

&lt;p&gt;The same MiniMax review produced a finding I declined, and the arithmetic is&lt;br&gt;
worth showing because it is the honest half of this whole approach.&lt;/p&gt;

&lt;p&gt;It called a per-directory split HIGH severity, on the grounds that&lt;br&gt;
"65 + 9 + 63 = 77, which is 60 short of 137".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;python3&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;print(65+9+63)&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="mi"&gt;137&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The split reconciles exactly. The row stands as written. An adversarial reviewer&lt;br&gt;
is a model pointed at the work with a narrow mandate, and it is fallible in&lt;br&gt;
exactly the way everything else in the loop is fallible. The layer only earns&lt;br&gt;
its keep if its findings go through the same evidence test the work does. Every&lt;br&gt;
finding it raised that day got checked; one of them did not survive.&lt;/p&gt;
&lt;h2&gt;
  
  
  The review that was drafted instead of dispatched
&lt;/h2&gt;

&lt;p&gt;Commit &lt;code&gt;91cd7c5&lt;/code&gt;, which landed in PR #94, fixed the worst process defect of the day, and it is the one I&lt;br&gt;
would have caught last if the gate auditor had not been looking.&lt;/p&gt;

&lt;p&gt;A record had shipped at v1.0.0 with a section containing two lens positions that&lt;br&gt;
the builder had written himself. The cannon was never dispatched. Somebody wrote&lt;br&gt;
what a reviewer might plausibly say instead of asking the reviewer. A draft of&lt;br&gt;
what a reviewer might say is not a review, and the record had been carrying it&lt;br&gt;
as one.&lt;/p&gt;

&lt;p&gt;When the real cannon ran, both lenses returned ACCEPT-WITH-CHANGES, the gate&lt;br&gt;
auditor returned NOT-READY on facts, and the invariant reviewer returned&lt;br&gt;
PASS-WITH-NOTES. Two of the findings were enforcement rather than prose, so the&lt;br&gt;
record went to a minor version instead of a patch, because v1.0.0 had been wrong&lt;br&gt;
about two things rather than merely silent on them.&lt;/p&gt;

&lt;p&gt;Three real behavior changes fell out of that dispatch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A privileged sign-in now revokes the person's other live privileged chains at&lt;br&gt;
that shop.&lt;/strong&gt; A session expiry bounds the session, and it does not bound the acts&lt;br&gt;
the session performed. Using the provisional constants as they stand today, a&lt;br&gt;
copied cookie mints a 24-hour invitation and a 15-minute enrollment code, and it&lt;br&gt;
leaves a permanent owner membership and a 30-day device credential standing&lt;br&gt;
after the session dies. Eviction is now an act&lt;br&gt;
the owner can perform. It is scoped to the same shop rather than sweeping a&lt;br&gt;
person globally, because the wider version would unilaterally widen another&lt;br&gt;
record's cross-tenant scope union from inside a bead that never argued for it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Naming a second owner on an invitation now re-presents the second factor in&lt;br&gt;
the request&lt;/strong&gt;, and refuses without it. Of every act in that flow, this is the one&lt;br&gt;
whose damage no expiry bounds: a second owner outlives every session, every&lt;br&gt;
token, and every device. It was extracted into its own transaction rather than&lt;br&gt;
folded into the existing call, so the lock-order lint reads the two anchors&lt;br&gt;
truthfully instead of being dodged by a merge.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The sign-in path took its own provisional per-identifier rate constant instead&lt;br&gt;
of borrowing the device class constant.&lt;/strong&gt; The measurement that forced it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;same-class refusals, sign-in path:   5.7 ms
device-class refusals:               449 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Constant in the body and not on the clock. On an anonymous internet-facing&lt;br&gt;
route, that is an enumeration oracle for who works at which shop.&lt;/p&gt;
&lt;h2&gt;
  
  
  The same failure outside software
&lt;/h2&gt;

&lt;p&gt;The second instance came out of &lt;code&gt;intent-os&lt;/code&gt;, in commit &lt;code&gt;03e22943&lt;/code&gt;: an&lt;br&gt;
independent adversarial audit of the partner-network legal packet. Six read-only&lt;br&gt;
streams plus eighteen scenarios, 177 findings, 25 root-cause groups.&lt;/p&gt;

&lt;p&gt;The v0.1 packet it audited had been drafted the same day, six and a half hours&lt;br&gt;
earlier, at commit &lt;code&gt;bedc4d4e&lt;/code&gt; (14:30 to 21:02). No reviewer had touched it. The&lt;br&gt;
&lt;code&gt;[COUNSEL:]&lt;/code&gt; markers in its own text say as much, and no &lt;code&gt;legal/review/&lt;/code&gt;&lt;br&gt;
directory existed until the audit commit created one. It had passed its author&lt;br&gt;
and been committed as a finished deliverable, which is a weaker gate than the&lt;br&gt;
Longbox records cleared and a more common one.&lt;/p&gt;

&lt;p&gt;What the second pass found:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every document named the wrong legal entity.&lt;/li&gt;
&lt;li&gt;A signature block was pre-filled with a non-office title, for a 50/50 LLC with
no signing authority on file.&lt;/li&gt;
&lt;li&gt;A flow-down was promised with no artifact behind it, and the packet
contradicted itself on precedence.&lt;/li&gt;
&lt;li&gt;Liability caps were left blank in a way that reads as an absence of any cap.&lt;/li&gt;
&lt;li&gt;The packet contradicted the firm's own doctrine on classification.&lt;/li&gt;
&lt;li&gt;The practitioner layer carried nothing on security, data, AI, or open source.&lt;/li&gt;
&lt;li&gt;It was about to be signed by a person in Germany, on a contractor form scoped
to US individuals only.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every one of those is a false or missing statement of fact in a document that&lt;br&gt;
was already being treated as done. There is no compiler anywhere near it, and there is&lt;br&gt;
no test suite either. The failure mode transferred cleanly anyway.&lt;/p&gt;

&lt;p&gt;The remediation is the part I would reuse. Every executable draft got a&lt;br&gt;
canonical banner at the top and above every signature row: DRAFT, ATTORNEY&lt;br&gt;
REVIEW REQUIRED, NOT APPROVED FOR SIGNATURE OR USE. Signer and title were left&lt;br&gt;
blank pending an open decision. The contractor form was renamed from "member" to&lt;br&gt;
"practitioner", restructured as a master agreement plus Work Orders, and held to&lt;br&gt;
US individuals only.&lt;/p&gt;

&lt;p&gt;The discipline that makes that audit trustworthy is what it refused to do. Every&lt;br&gt;
legal judgment was registered as an open decision (D-01 through D-22) or a&lt;br&gt;
counsel question (C-01 through C-28) rather than being decided. The audit's&lt;br&gt;
authority stops where counsel's begins, and an audit that quietly rules on a&lt;br&gt;
question it has no standing to rule on has become the thing it was checking.&lt;/p&gt;

&lt;p&gt;It also shipped an enforcement script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ci/validate-legal-packet.sh     &lt;span class="c"&gt;# 12 checks&lt;/span&gt;
pnpm run validate:legal-packet  &lt;span class="c"&gt;# wired into CI&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Twelve checks, plus a planted-fixture self-test: every check has to be shown to&lt;br&gt;
fire against a deliberately broken fixture before it counts. A check that has&lt;br&gt;
never failed is a check nobody has tested.&lt;/p&gt;

&lt;p&gt;Source integrity was handled the same way. The files under &lt;code&gt;legal/sources/&lt;/code&gt; were&lt;br&gt;
hash-matched against a manifest recorded before any edit, and 14 of 14 matched.&lt;/p&gt;

&lt;p&gt;Two facts were explicitly marked provisional and not verified in that session:&lt;br&gt;
the Alabama statutory texts, because Justia returned 403 and the legislature&lt;br&gt;
site was unresolvable; and the Secretary of State record, because it sits behind&lt;br&gt;
an interactive form. Marking a fact as not verified, by name, with the reason,&lt;br&gt;
is the same discipline as the rest of the day pointed inward. The alternative is&lt;br&gt;
a packet where verified and assumed look identical to the next reader.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the second lane cost
&lt;/h2&gt;

&lt;p&gt;Numbers first, because this approach is not free and the bill should be visible.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Measure, 2026-09-05&lt;/th&gt;
&lt;th&gt;What the first review produced&lt;/th&gt;
&lt;th&gt;What the second lane added&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Statements of fact repaired&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;about 20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rulings changed by the repairs&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security claims withdrawn as measured false&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Evidence rungs downgraded&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ratified records restored after rebase damage&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reviewer findings declined on arithmetic&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The zero in the second row is the interesting one. Not one repair moved a&lt;br&gt;
decision. Every ruling the first review cleared survived the second review&lt;br&gt;
intact. The code was right the whole time, and the record describing it was&lt;br&gt;
wrong in about twenty places.&lt;/p&gt;

&lt;p&gt;The other number, 42,385 lines added, deserves an honest reading too. A large fraction of&lt;br&gt;
that day's diff is records about records: registers, appends, gate audits,&lt;br&gt;
residual rows, claim ids. That is the cost line.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tradeoffs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;This is expensive, and the expense is mostly wall-clock.&lt;/strong&gt; Every one of those&lt;br&gt;
four repair commits came after the feature work was already merged-quality. The&lt;br&gt;
gate auditor, the invariant reviewer, the two lenses, and the adversarial pass&lt;br&gt;
each add a round trip, and each audit cycle can come back NOT-READY on paperwork&lt;br&gt;
that changes no behavior. A team optimizing for cycle time will hate this and&lt;br&gt;
will be right to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The audit trail is load-bearing, which means it is also a liability.&lt;/strong&gt; Append&lt;br&gt;
logs, ratified records, claim ids, and version pins only work if nothing edits&lt;br&gt;
them in place. Two of the day's repairs exist because a routine rebase damaged&lt;br&gt;
records nobody was watching. The heavier the paper trail, the more surface a&lt;br&gt;
mechanical operation has to corrupt, and rebases do not read your conventions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fabricating a review is a live failure mode.&lt;/strong&gt; Commit &lt;code&gt;91cd7c5&lt;/code&gt; exists because&lt;br&gt;
somebody drafted the two lens positions instead of dispatching the cannon, and&lt;br&gt;
that got all the way to v1.0.0. A process with a named review step invites&lt;br&gt;
someone to satisfy the step's shape without paying its cost. The only defense I&lt;br&gt;
have found is a separate auditor whose mandate includes checking that the review&lt;br&gt;
happened at all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The adversarial layer is itself unreliable.&lt;/strong&gt; The same MiniMax review that&lt;br&gt;
produced the best correction of the day also produced a HIGH-severity finding&lt;br&gt;
built on 65 + 9 + 63 = 77. If you take these findings on authority you will&lt;br&gt;
degrade your record instead of improving it. Every finding has to be checked,&lt;br&gt;
which means the second lane needs a third posture: audit the auditor.&lt;/p&gt;

&lt;p&gt;The scope where this pays is narrow. If nobody outside the session that wrote a&lt;br&gt;
record ever cites it, the second lane buys nothing. The value shows up once a&lt;br&gt;
claim in a document becomes an input to a later decision, a partner&lt;br&gt;
conversation, a security posture, or a signature. Most weekend projects have no&lt;br&gt;
record with that property. A multi-tenant system holding other people's data&lt;br&gt;
does, and so does a stack of contracts about to be signed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where a claims audit sits in wider practice
&lt;/h2&gt;

&lt;p&gt;The idea is not new anywhere except in how it gets applied to AI-generated work.&lt;br&gt;
The analogy I keep reaching for is accounting reconciliation, where the entry&lt;br&gt;
and the check on the entry are deliberately different jobs. I have no artifact&lt;br&gt;
that says other fields adopted the split for the reason I am describing, so take&lt;br&gt;
that as a shape I find useful rather than as evidence from the day.&lt;/p&gt;

&lt;p&gt;Software collapsed those into one step called code review, and it mostly worked&lt;br&gt;
while humans wrote both the code and the paragraph describing it, because the&lt;br&gt;
person typing the paragraph had just done the work and remembered the details.&lt;/p&gt;

&lt;p&gt;That property weakens when an agent writes the paragraph. Agents produce fluent,&lt;br&gt;
plausible, well-structured prose about work at a rate no human reviewer reads&lt;br&gt;
carefully, and the failure mode is specific: the sentence is shaped exactly like&lt;br&gt;
a true sentence. "All twelve invariants proved against a database" reads&lt;br&gt;
identically to the accurate version. Only a pass that opens the artifact and&lt;br&gt;
counts can tell them apart.&lt;/p&gt;

&lt;p&gt;The rung rule generalizes better than anything else I took from the day. Every&lt;br&gt;
claim sits at a rung: argued, implied, observed, measured, proved. Every artifact&lt;br&gt;
supports some rung. Enforcing that the claim never outranks its artifact is a&lt;br&gt;
mechanical check a reviewer can perform without domain expertise, and it caught&lt;br&gt;
both the "proved" downgrade and the oracle withdrawal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Also shipped
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;intent-os&lt;/code&gt; also carried a second track that day, ten commits of an eleven-commit&lt;br&gt;
day. A gateway&lt;br&gt;
business-plan vision cluster was filed at v0.1 verbatim with five gap beads,&lt;br&gt;
advanced to v0.2 (&lt;code&gt;dbd3cd9f&lt;/code&gt;, &lt;code&gt;8cccfbe0&lt;/code&gt;), then put through a council review (&lt;code&gt;ac07d920&lt;/code&gt;): 13 thinker-canon seats plus&lt;br&gt;
an SI practice partner and a hyperscaler partner-program director, over five&lt;br&gt;
adversarially re-verified research packets, with dissent preserved and nine&lt;br&gt;
follow-on beads opened. The recorded rationale for the shape was that a workflow&lt;br&gt;
of 26 agents beat a single synthesis pass, because the seats had to argue&lt;br&gt;
independently before any dissent existed to preserve.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;intent-solutions-landing&lt;/code&gt; took one field-notes content commit.&lt;br&gt;
&lt;code&gt;claude-code-plugins&lt;/code&gt; took seven commits on main: three dependency chores, a&lt;br&gt;
marketplace-sync fix for Windows, two plugin feature commits, and the&lt;br&gt;
dual-publish of the field note.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Can code review find false claims in the documentation?
&lt;/h3&gt;

&lt;p&gt;Code review checks whether the decisions are right. It almost never checks whether the paragraph describing the decision is accurate. A review that only checks decisions leaves the prose ungated, and the prose is what everyone downstream cites. In the 2026-09-05 example, roughly twenty statements of fact got repaired across the day, and every ruling the first review cleared survived the second review intact.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is an evidence rung?
&lt;/h3&gt;

&lt;p&gt;Every claim sits at a rung (argued, implied, observed, measured, proved) and every artifact supports some rung. The rule is that a claim may not use a stronger rung than the artifact it cites. It is a mechanical check a reviewer can perform without domain expertise. On 2026-09-05 one claim moved from "proved able to fail" to a recorded local reproduction, because the artifact was a CI run with the flag already on, which never showed the flag was the reason.&lt;/p&gt;

&lt;h3&gt;
  
  
  When should you run a second review lane for claims?
&lt;/h3&gt;

&lt;p&gt;The scope where this pays is narrow. If nobody outside the session that wrote a record ever cites it, the second lane buys nothing. The value shows up once a claim in a document becomes an input to a later decision, a partner conversation, a security posture, or a signature. A multi-tenant system holding other people's data qualifies, and so does a stack of contracts about to be signed.&lt;/p&gt;

&lt;p&gt;{&lt;br&gt;
  "&lt;a class="mentioned-user" href="https://dev.to/context"&gt;@context&lt;/a&gt;": "&lt;a href="https://schema.org" rel="noopener noreferrer"&gt;https://schema.org&lt;/a&gt;",&lt;br&gt;
  "@type": "FAQPage",&lt;br&gt;
  "mainEntity": [&lt;br&gt;
    {"@type": "Question", "name": "Can code review find false claims in the documentation?", "acceptedAnswer": {"@type": "Answer", "text": "Code review checks whether the decisions are right. It almost never checks whether the paragraph describing the decision is accurate. A review that only checks decisions leaves the prose ungated, and the prose is what everyone downstream cites. In the 2026-09-05 example, roughly twenty statements of fact got repaired across the day, and every ruling the first review cleared survived the second review intact."}},&lt;br&gt;
    {"@type": "Question", "name": "What is an evidence rung?", "acceptedAnswer": {"@type": "Answer", "text": "Every claim sits at a rung (argued, implied, observed, measured, proved) and every artifact supports some rung. The rule is that a claim may not use a stronger rung than the artifact it cites. It is a mechanical check a reviewer can perform without domain expertise. On 2026-09-05 one claim moved from proved able to fail to a recorded local reproduction, because the artifact was a CI run with the flag already on, which never showed the flag was the reason."}},&lt;br&gt;
    {"@type": "Question", "name": "When should you run a second review lane for claims?", "acceptedAnswer": {"@type": "Answer", "text": "The scope where this pays is narrow. If nobody outside the session that wrote a record ever cites it, the second lane buys nothing. The value shows up once a claim in a document becomes an input to a later decision, a partner conversation, a security posture, or a signature. A multi-tenant system holding other people's data qualifies, and so does a stack of contracts about to be signed."}}&lt;br&gt;
  ]&lt;br&gt;
}&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Posts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://startaitools.com/posts/wrong-mode-green-is-not-a-gate/" rel="noopener noreferrer"&gt;Wrong-Mode Green Is Not a Gate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://startaitools.com/posts/the-lane-that-reviewed-nothing/" rel="noopener noreferrer"&gt;Every Check Should Report What It Did Not Look At&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://startaitools.com/posts/the-commit-the-test-actually-installed/" rel="noopener noreferrer"&gt;Bind the Receipt to the Commit It Installed&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>security</category>
      <category>testing</category>
      <category>architecture</category>
      <category>aiagents</category>
    </item>
    <item>
      <title>Photo to Listing: Barcode Decoding and LLM Re-rank</title>
      <dc:creator>Jeremy Longshore</dc:creator>
      <pubDate>Fri, 04 Sep 2026 10:35:18 +0000</pubDate>
      <link>https://dev.to/jeremy_longshore/photo-to-listing-barcode-decoding-and-llm-re-rank-1135</link>
      <guid>https://dev.to/jeremy_longshore/photo-to-listing-barcode-decoding-and-llm-re-rank-1135</guid>
      <description>&lt;p&gt;A comic shop employee photographs a back issue on a phone. The system has to come back with the right title, the right issue number, and the right variant, because a first-print variant and a common reprint of the same book are the same picture with different economics. That is the identification problem in &lt;strong&gt;intent-longbox&lt;/strong&gt;, a photo to listing pipeline that ended 2026-09-01 at v0.2.1 after eleven commits.&lt;/p&gt;

&lt;p&gt;The research that preceded the build settled the architecture in one finding: LLM vision alone is not viable for issue-exact and variant-exact identification. Every incumbent that actually works in this space runs image-similarity retrieval against a reference cover corpus. The model is a ranker, never the source of truth.&lt;/p&gt;

&lt;p&gt;So the pipeline puts the &lt;a href="https://startaitools.com/posts/llm-legible-deterministic-architecture/" rel="noopener noreferrer"&gt;deterministic parts first&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;barcode decode → candidate retrieval → LLM re-rank → human confirm → condition + price → Shopify draft
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing publishes without a person. The Shopify product lands as a DRAFT for owner review. The pilot shop is Gotham City Limit, running free.&lt;/p&gt;

&lt;p&gt;The deterministic front of that chain is a barcode parser with no model in it at all. Post-1990 comics carry a 12-digit UPC-A that identifies the series, plus a 5-digit UPC supplement encoding issue, cover variant, and printing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;supp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;digits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;upc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;supplement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;supp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;issue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;supp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="na"&gt;cover&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;supp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
    &lt;span class="na"&gt;printing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;supp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When that supplement is readable, the variant question is already answered by arithmetic. The model never gets asked.&lt;/p&gt;

&lt;p&gt;The honest version of that diagram is that the retrieval leg is not built yet. v0 ships barcode plus vision plus human pick, with no similarity index behind the candidate step. So a barcode miss (pre-1990 stock, a damaged code, a variant with no UPC) falls to vision plus the gate below plus a mandatory human confirmation, which is the weakest path in the system and the one the pilot is meant to measure. That gap is tracked as the project's top open decision, not as a solved problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  The database refuses to mutate
&lt;/h2&gt;

&lt;p&gt;Every event in a scan session is a separate immutable row, which makes the table an audit trail rather than a current-state cache. &lt;code&gt;scan_session&lt;/code&gt; is the identity. &lt;code&gt;candidate_set&lt;/code&gt; holds the deterministic result (barcode decode plus similarity k-NN, FK'd to a &lt;code&gt;corpus_version&lt;/code&gt;). &lt;code&gt;llm_rerank&lt;/code&gt; holds the probabilistic value: provider, model, prompt hash, the verbatim response, confidence, band, contradiction flag, tokens, cost. It annotates the candidate set. It cannot edit it.&lt;/p&gt;

&lt;p&gt;Then &lt;code&gt;human_confirmation&lt;/code&gt;, &lt;code&gt;condition_assessment&lt;/code&gt;, &lt;code&gt;pricing_snapshot&lt;/code&gt;, &lt;code&gt;shopify_draft&lt;/code&gt;, &lt;code&gt;cost_log&lt;/code&gt;. Every shop-scoped table carries &lt;code&gt;shop_id&lt;/code&gt;. The only UPDATE anywhere in the codebase is on &lt;code&gt;scan_session.status&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The obvious way to enforce append-only is code discipline. Write no UPDATE statements, review for them, move on. I rejected that, because it holds exactly as long as every future query is well behaved. A migration script, a hotfix, or one psql session at two in the morning ends the guarantee quietly, and the tell is that the audit trail looks fine afterward.&lt;/p&gt;

&lt;p&gt;So the rule lives in the database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="k"&gt;REPLACE&lt;/span&gt; &lt;span class="k"&gt;FUNCTION&lt;/span&gt; &lt;span class="n"&gt;forbid_mutation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;RETURNS&lt;/span&gt; &lt;span class="k"&gt;trigger&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="err"&gt;$$&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;
  &lt;span class="n"&gt;RAISE&lt;/span&gt; &lt;span class="n"&gt;EXCEPTION&lt;/span&gt; &lt;span class="s1"&gt;'table % is append-only (Hickey model): % not allowed'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TG_TABLE_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TG_OP&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;$$&lt;/span&gt; &lt;span class="k"&gt;LANGUAGE&lt;/span&gt; &lt;span class="n"&gt;plpgsql&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;DO&lt;/span&gt; &lt;span class="err"&gt;$$&lt;/span&gt;
&lt;span class="k"&gt;DECLARE&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;
  &lt;span class="n"&gt;FOREACH&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="n"&gt;ARRAY&lt;/span&gt; &lt;span class="n"&gt;ARRAY&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'corpus_version'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'scan_photo'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'candidate_set'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'llm_rerank'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'human_confirmation'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'condition_assessment'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'pricing_snapshot'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'shopify_draft'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'cost_log'&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;LOOP&lt;/span&gt;
    &lt;span class="k"&gt;EXECUTE&lt;/span&gt; &lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s1"&gt;'CREATE TRIGGER %I_append_only BEFORE UPDATE OR DELETE ON %I FOR EACH ROW EXECUTE FUNCTION forbid_mutation()'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="n"&gt;LOOP&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="err"&gt;$$&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verified against a real Postgres, not asserted in a comment. An UPDATE on &lt;code&gt;cost_log&lt;/code&gt; raises &lt;code&gt;table cost_log is append-only (Hickey model)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;One more schema decision belongs here. Condition is a grade range label, and no numeric grade type exists anywhere in the schema, the API, the prompts, or the UI copy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;grade_range_low&lt;/span&gt;  &lt;span class="nb"&gt;text&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;CHECK&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;grade_range_low&lt;/span&gt;  &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'PR'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'FR'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'GD'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'VG'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'FN'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'VF'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'NM'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="n"&gt;grade_range_high&lt;/span&gt; &lt;span class="nb"&gt;text&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;CHECK&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;grade_range_high&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'PR'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'FR'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'GD'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'VG'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'FN'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'VF'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'NM'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A 9.4 is a claim a phone photo does not entitle anyone to make. If the type does not exist, nobody adds it later under deadline pressure.&lt;/p&gt;

&lt;h2&gt;
  
  
  The evidence contradiction gate
&lt;/h2&gt;

&lt;p&gt;Confidence scores from a model are self-reported. Asking for one and thresholding on it is the cheap version of a quality gate, and it fails in the direction you care about, because a model is most fluent when it is wrong about a plausible thing.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;VisionProvider&lt;/code&gt; interface therefore requires structured evidence alongside the answer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/** REQUIRED structured evidence. The contradiction gate's raw material (R7). */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Evidence&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;issue_number_read&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;price_box_text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;logo_era_guess&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The prompt states the same requirement in the model's own terms:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- evidence fields are REQUIRED: report exactly what you can read on the cover
  (issue number printed, cover price box text, publisher logo era guess).
  Use null only when genuinely unreadable.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now there is something to check. &lt;code&gt;src/services/rerank.ts&lt;/code&gt; cross-validates each field against the top candidate's metadata. Issue number read against the candidate's issue. Cover price against a coarse US newsstand era table. Logo era decade against the candidate year:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;evidence&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price_box_text&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;top&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;year&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;priceMatch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;evidence&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price_box_text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;(\d&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;)\s&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;¢c&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;|&lt;/span&gt;&lt;span class="se"&gt;\$\s&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;(\d&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;(?:\.\d{1,2})?)&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;priceMatch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="nx"&gt;priceMatch&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;priceMatch&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;priceMatch&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;era&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;priceEraBounds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cents&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;era&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;top&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;year&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;era&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;min&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;top&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;year&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;era&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;max&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;reasons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s2"&gt;`price_box_text "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;evidence&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price_box_text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;" implies ~&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;era&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;min&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;era&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;max&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, contradicts candidate year &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;top&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;year&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The era bounds are deliberately loose. The gate catches decade-scale misses and does not quibble about a two-year overlap.&lt;/p&gt;

&lt;p&gt;A contradiction then costs the model its fast path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;applyContradiction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;band&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Band&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;contradiction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Band&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;contradiction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;band&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;band&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;high&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;medium&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;band&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three bands drive the phone UI. High is a one-tap confirm. Medium is a candidate grid with a forced pick. Low is manual search. Downgrading high to medium means a confident but self-contradicting answer costs the employee one extra tap instead of putting a wrong book into inventory.&lt;/p&gt;

&lt;p&gt;The transferable piece has nothing to do with comics. Do not ask a model how sure it is. Make it report the specific things it read, then check those against something deterministic you already trust.&lt;/p&gt;

&lt;p&gt;Seeded cases in the test suite all flag and downgrade: a wrong issue number read, a twelve cent price box on a 1988 book, a 1960s logo on a modern year.&lt;/p&gt;

&lt;p&gt;The provider seam behind that gate is a &lt;a href="https://startaitools.com/posts/the-moat-is-the-trust-layer-nexus-byok-rag/" rel="noopener noreferrer"&gt;bring your own key provider architecture&lt;/a&gt; per shop, with an Anthropic adapter (Messages API, image blocks, &lt;code&gt;claude-sonnet-5&lt;/code&gt; as default and reference model) and an OpenAI-compatible adapter (chat completions, &lt;code&gt;image_url&lt;/code&gt; data URIs). Resolution order is a gateway override first, then a shop credential row whose &lt;code&gt;key_ref&lt;/code&gt; names an env var, then a global env fallback. Raw keys never enter the database, only refs to env var names. Two pieces of reliability lore carried over from the estate's existing provider registry shape in &lt;code&gt;@intentsolutions/refiner&lt;/code&gt; and the Transport seam in &lt;code&gt;@intentsolutions/jrig-cli&lt;/code&gt;: a 2048 max-output-token floor, and a parser that strips &lt;code&gt;&amp;lt;think&amp;gt;&lt;/code&gt; blocks before it goes looking for JSON.&lt;/p&gt;

&lt;h2&gt;
  
  
  One snapshot per source, and no source can block
&lt;/h2&gt;

&lt;p&gt;The 23:56 commit added a second seam. A &lt;code&gt;PricingProvider&lt;/code&gt; declares a &lt;code&gt;source&lt;/code&gt;, a &lt;code&gt;kind&lt;/code&gt; of &lt;code&gt;live_asks&lt;/code&gt; or &lt;code&gt;historical_fmv&lt;/code&gt;, and returns comps plus a low/median/high summary plus &lt;code&gt;fetched_at&lt;/code&gt; plus a stub flag. Two adapters implement it: a new eBay Browse adapter (OAuth2 client-credentials app token, cached until near expiry, query built from title, issue number, and variant against the comics category) and PriceCharting refined behind the same interface.&lt;/p&gt;

&lt;p&gt;Two decisions in that step went against the obvious version.&lt;/p&gt;

&lt;p&gt;First, provider isolation over sequencing. Calling two pricing APIs in a row is simpler to write and means the second one never runs when the first one has a bad morning:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;settled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;allSettled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getComps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;shopCtx&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A failed source is reported in the outcome list with its error and writes no snapshot row, because nothing was fetched. The other source still prices the book.&lt;/p&gt;

&lt;p&gt;Second, one snapshot row per source, with the overall suggestion stamped on every row:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;fulfilled&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;`INSERT INTO pricing_snapshot
       (scan_session_id, shop_id, source, query, comps, suggested_cents, override_cents, policy_id, fetched_at)
     VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9) RETURNING id`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sessionId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shopId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;queryText&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;comps&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nx"&gt;suggested&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;overrideCents&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;policyId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fetched_at&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Per-source suggested prices would have been more honest-looking and worse to consume. The draft step would have needed to know which source wins before it could read a price, which is ordering ambiguity in a table that no one is allowed to correct afterward. Stamping the overall figure on every row keeps one rule for the draft step: the latest snapshot carries the price of record.&lt;/p&gt;

&lt;p&gt;Precedence is fixed rather than clever:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;pickDrivingResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PricingResult&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="nx"&gt;PricingResult&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;real&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PricingResult&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stub&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;comps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;historical_fmv&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;real&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt;
    &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;live_asks&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;real&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt;
    &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;real&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Historical fair market value beats live asking prices, because an ask is a wish. When neither source has real comps, the shop's policy floor wins. The UI shows both sources side by side, highlights the driving one, and labels stubs as stubs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Governance, tests, and the release cycle
&lt;/h2&gt;

&lt;p&gt;Governance came first, at 18:07, through the &lt;code&gt;/repo-dress&lt;/code&gt; pass: LICENSE, SECURITY.md, CONTRIBUTING.md, CODE_OF_CONDUCT.md, SUPPORT.md, AGENTS.md, CI. The 18:12 commit authored the six master planning docs (business case, PRD with R1 through R20 MoSCoW-tagged, architecture, user journeys, technical spec, status) alongside the index and the project CLAUDE.md, which brought &lt;code&gt;000-docs/&lt;/code&gt; to eight filed documents with the competitor analysis and the approved build plan already in the tree. Then an isolated beads workspace with prefix &lt;code&gt;longbox&lt;/code&gt;. Five automated release commits took version.txt from v0.1.0 to v0.2.1.&lt;/p&gt;

&lt;p&gt;The API is shop-scoped by path prefix, &lt;code&gt;/api/shops/:shopId/scan-sessions&lt;/code&gt;, chosen over a header because a path is visible in logs, cacheable, and curl-friendly. Onboarding a shop is one command, &lt;code&gt;pnpm register-shop&lt;/code&gt;. Every model call writes a cost row from day one.&lt;/p&gt;

&lt;p&gt;Verification at end of day: &lt;code&gt;pnpm lint&lt;/code&gt;, &lt;code&gt;format:check&lt;/code&gt;, and &lt;code&gt;typecheck&lt;/code&gt; green. 118 unit tests, up from 92 at the core-pipeline commit. Coverage 99.67% of lines against a floor of 80. Fourteen integration and smoke tests green against a dockerized &lt;code&gt;postgres:16&lt;/code&gt;, including one that asserts two snapshot rows come out of a single price call. Migration &lt;code&gt;002&lt;/code&gt; extends the &lt;code&gt;shop_credentials.kind&lt;/code&gt; CHECK with &lt;code&gt;ebay&lt;/code&gt; and leaves &lt;code&gt;001&lt;/code&gt; untouched. &lt;code&gt;tests/TESTING.md&lt;/code&gt; was re-pinned with &lt;code&gt;audit-harness init&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this does not do yet
&lt;/h2&gt;

&lt;p&gt;Both pricing sources are stubs in real terms right now. PriceCharting's live field mapping needs verification the day the Premium token lands, and eBay returns a flagged stub without credentials.&lt;/p&gt;

&lt;p&gt;No similarity index exists. That is a locked decision rather than an oversight: v0 ships barcode plus vision plus human pick, and if the pilot shows real misses the plan is to buy before building. Ximilar sells a commercial comics visual-search API and a quote is pending. A self-built cover-image index would rest on a fair-use posture instead of a granted license, which is the project's top logged risk.&lt;/p&gt;

&lt;p&gt;The CI static eval regression set is a Phase 2 exit item that has not been built. The &lt;code&gt;human_confirmation&lt;/code&gt; table is designed to grow into that eval set, and it currently holds nothing. The UI &lt;code&gt;override_cents&lt;/code&gt; smoke assertion is still pending.&lt;/p&gt;

&lt;p&gt;And none of this has met a real comic. Every number above came from a test suite and a Docker container. The pilot has not run.&lt;/p&gt;

&lt;p&gt;Also shipped that day, both routine pipeline output: the blog automation dual-published the previous day's post &lt;code&gt;working-is-not-proven&lt;/code&gt; to tonsofskills.com/blog, and the comehomealabama journal published a piece on July coastal market numbers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why not use a vision model alone for comic identification?
&lt;/h3&gt;

&lt;p&gt;Issue-exact and variant-exact identification is retrieval work. Every incumbent that works in this space runs image similarity against a reference cover corpus, which is why the model here sits in the re-rank seat instead of the identifier seat. A first print and a common reprint of the same book are the same picture with different economics, and that difference is carried by metadata rather than by the image.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should barcode decoding run before or after the vision model?
&lt;/h3&gt;

&lt;p&gt;Before. Post-1990 comics carry a 12-digit UPC-A plus a 5-digit supplement that encodes issue, cover variant, and printing, so a readable supplement answers the variant question by arithmetic and the model is never asked. Vision is the fallback for the books that arithmetic cannot reach, and today that fallback runs without a similarity index behind it.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do you stop a vision model from confidently returning a wrong answer?
&lt;/h3&gt;

&lt;p&gt;Require structured evidence alongside the answer, then check that evidence against something deterministic. This pipeline asks for the issue number read, the cover price box text, and the logo era, then cross-validates each against the top candidate's metadata. A contradiction downgrades the confidence band from high to medium, which costs the employee one extra tap and keeps a wrong book out of inventory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Posts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://startaitools.com/posts/building-cad-dxf-agent-from-zero-to-v010/" rel="noopener noreferrer"&gt;Shipping a CAD Agent from Zero: DXF Parsing, Edit Engines, and LLM Planner Interfaces&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://startaitools.com/posts/every-safety-gate-has-a-failure-direction/" rel="noopener noreferrer"&gt;Every Safety Gate Has a Failure Direction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://startaitools.com/posts/noise-robust-signed-llm-judge-evals/" rel="noopener noreferrer"&gt;Noise-Robust LLM-Judge Evals: Don't Sign a Coin Flip&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>architecture</category>
      <category>aiagents</category>
      <category>typescript</category>
      <category>testing</category>
    </item>
    <item>
      <title>Every Claim Needs a Shipped Source and an Executable Proof</title>
      <dc:creator>Jeremy Longshore</dc:creator>
      <pubDate>Wed, 02 Sep 2026 14:49:15 +0000</pubDate>
      <link>https://dev.to/jeremy_longshore/every-claim-needs-a-shipped-source-and-an-executable-proof-3l0e</link>
      <guid>https://dev.to/jeremy_longshore/every-claim-needs-a-shipped-source-and-an-executable-proof-3l0e</guid>
      <description>&lt;p&gt;I told GPT 5.6 Luna, running through Codex, to &lt;code&gt;finish teh epics and beads&lt;/code&gt; on the plugins repo. It ran for about 361 minutes across 2 sessions and 187 turns, and it closed nothing. No file mutated, no Beads record touched, no GitHub state changed. Its closing line was that the worktree was clean at &lt;code&gt;origin/main&lt;/code&gt; &lt;code&gt;3c5be4a5981ed5089deedff53d18136b9848a18c&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That is not a failure report. Asked to finish three epics, the honest deliverable turned out to be an inventory of what "finished" would actually require, and the five open beads had five different meanings of "not done". Two of them are closable by writing code. The other three need an owner clicking a setting, a calendar to run out, and a record corrected to match reality.&lt;/p&gt;

&lt;p&gt;The same gap kept showing up until the day ended, and three of the day's fixes were to &lt;a href="https://startaitools.com/posts/a-green-result-only-covers-what-it-ran/" rel="noopener noreferrer"&gt;proof machinery that could not be trusted&lt;/a&gt; about its own state: a gate runner manufacturing false failures, a render check poisoned by its own output, and a liveness marker that could not tell quiet from dead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Five ways a finished feature is still not done
&lt;/h2&gt;

&lt;p&gt;The audit read Epics 6, 7 and 10 against Blueprint 727, the live Beads Dolt database, &lt;code&gt;origin/main&lt;/code&gt; code, tests, workflows, branches and PRs. Read-only throughout. What came back was a taxonomy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code live, acceptance failing at the platform.&lt;/strong&gt; &lt;code&gt;claude-nfzl.6&lt;/code&gt; ships in &lt;code&gt;242d8e051&lt;/code&gt;: &lt;code&gt;validate-plugins.yml&lt;/code&gt;, &lt;code&gt;check-marketplace-compliance-baseline.py&lt;/code&gt;, &lt;code&gt;.github/CODEOWNERS&lt;/code&gt;, and 13 focused tests. Then &lt;code&gt;gh api repos/.../branches/main/protection&lt;/code&gt; returns &lt;code&gt;required_approving_review_count=0&lt;/code&gt; and &lt;code&gt;require_code_owner_reviews=false&lt;/code&gt;. The gate is written, committed and switched off. Nothing in the repository can close that bead. It needs an owner clicking a setting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Calendar-gated, not code-gated.&lt;/strong&gt; &lt;code&gt;claude-nfzl.7&lt;/code&gt; has PR #1384 merged as &lt;code&gt;b786149e1&lt;/code&gt;, R2 and R4 code live, and a full-corpus run passing in about 58 seconds across 2053 live triples with zero newcomers. The only thing outstanding is a mandatory two-week R1 observation window and a flap receipt. Time closes that one. Code cannot.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Complete but stale.&lt;/strong&gt; &lt;code&gt;claude-jqvw.11&lt;/code&gt; runs &lt;code&gt;check-mirror-licenses.mjs&lt;/code&gt; green at 36 of 36 configured sources and 36 of 36 &lt;code&gt;.source.json&lt;/code&gt; mirrors, with sync hard-failing on a missing license include. Blueprint and Beads still carry the historical 63/63 denominator. The record is wrong, not the code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Green suite, missing red run.&lt;/strong&gt; &lt;code&gt;claude-jqvw.1&lt;/code&gt; has the whole chain working: tag, GitHub Release, reassertion, npm publish, with &lt;code&gt;npm-publication-lock.test.mjs&lt;/code&gt; passing 11 of 11. What it does not have is the required fault-injection RED run proving no orphan npm publication and retained signed evidence-row proof. A passing test says the happy path holds. It says nothing about the failure mode you built the lock for.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flag exists, workflow never calls it.&lt;/strong&gt; The evidence emitter supports &lt;code&gt;--certification-report&lt;/code&gt;. &lt;code&gt;.github/workflows/emit-evidence.yml&lt;/code&gt; never generates or passes a real one, so only catalog, unicode and required-context rows get signed. &lt;code&gt;claude-snmr.5&lt;/code&gt; is open because of that, and &lt;code&gt;claude-snmr.6&lt;/code&gt; is explicitly blocked behind it.&lt;/p&gt;

&lt;p&gt;The audit also decomposed a 79-entry corpus shrink (2132 pinned against 2053 live) into 78 &lt;code&gt;E-MISSING-REQUIRED-SECTION&lt;/code&gt; plus 1 &lt;code&gt;E-FRONTMATTER&lt;/code&gt;, rather than treating it as one bot-authored rule change. Last baseline commit was bot PR #1367 on Aug 27. And mid-run another agent modified &lt;code&gt;freshie/scripts/promote-to-curated.py&lt;/code&gt; and moved the branch to &lt;code&gt;fix/curated-promotion-cohort-parity&lt;/code&gt;. The auditor refused to reset or touch it and took all its Epic 6 evidence from read-only Git views of &lt;code&gt;origin/main&lt;/code&gt; instead. That is the correct call in a shared working tree, and it is a call I have watched agents get wrong.&lt;/p&gt;

&lt;p&gt;Merged in that repo the same day anyway: PR #1401 (&lt;code&gt;3c5be4a59&lt;/code&gt;, secure projections and Snowflake, the same commit the auditor later signed off as its clean baseline), PR #1403 (Snowflake operator skills), and &lt;code&gt;d6d14da83&lt;/code&gt; unifying the freshie curated promotion cohort.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why not just close the beads
&lt;/h3&gt;

&lt;p&gt;Because a closed bead that traces back to switched-off branch protection is worse than an open one. An open bead is a question. A closed bead is an answer, and nobody re-audits an answer. Convert the first into the second and you have not finished the work, you have deleted the only record that the work is unfinished. Six hours of audit output that closes nothing is cheaper than one wrong close, because the wrong close comes back as a production surprise with no bead pointing at it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing the requirement down as an enforced file
&lt;/h2&gt;

&lt;p&gt;While that audit ran, the Omarchy fleet moved: &lt;code&gt;omarchy-widget-template&lt;/code&gt; plus 15 &lt;code&gt;omarchy-*-entry&lt;/code&gt; repos: docket, quiet-queue, foundry, loose-ends, bazaar, capture-conveyor, listening-post, crew-chief, desk-transition, flow-boundary, wait-state, workspace-storyboard, x-files, mlb-booth and pit-wall. The commit shapes repeat: &lt;code&gt;test: certify &amp;lt;X&amp;gt; on Buzz&lt;/code&gt;, &lt;code&gt;chore: sync canonical Omarchy gates&lt;/code&gt;, &lt;code&gt;fix: bind &amp;lt;X&amp;gt; marketplace claims&lt;/code&gt;, &lt;code&gt;test: refresh &amp;lt;X&amp;gt; Buzz proof&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The artifact worth naming is 18 lines of markdown in the template, &lt;code&gt;contracts/marketplace.md&lt;/code&gt;, from commit &lt;code&gt;0607dcc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Marketplace claim ledger&lt;/span&gt;

Replace this template ledger before calling a generated plugin submission-ready.
Every meaningful listing claim needs a shipped source and an executable proof.
Do not infer behavior from a mockup, README, test name, or intended design.

| Claim | Shipped source | Executable proof |
|---|---|---|
| Visible bar outcome and primary panel action | &lt;span class="sb"&gt;`BarWidget.qml`&lt;/span&gt;, &lt;span class="sb"&gt;`Panel.qml`&lt;/span&gt; | plugin-specific contract and interaction tests |
| Data source, scope, cadence, and bounds | service QML, &lt;span class="sb"&gt;`Model.js`&lt;/span&gt;, or shipped helper | fixture-backed unit, boundary, and failure tests |
| Local writes, network use, credentials, and explicit exclusions | every shipped runtime path | security contract tests plus canonical gates |
| Marketplace image tells the same product story | &lt;span class="sb"&gt;`assets/banner.svg`&lt;/span&gt;, deterministic E2E fixture | hash-bound Buzz render receipt and visual approval |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two columns per claim, and both are mandatory. A test name is not a proof. A mockup is not a source. The ledger also fixes the description rule so it stops being a matter of taste: the final listing description and &lt;code&gt;barWidget.description&lt;/code&gt; must be identical, exactly 500 characters, name the product, explain what appears in the bar or panel, state what the user can do, and disclose the material trust boundary.&lt;/p&gt;

&lt;p&gt;A markdown file nobody enforces is a wish. The same commit added six lines to &lt;code&gt;tests/contract.test.js&lt;/code&gt;, five assertions plus the read, so the ledger cannot be quietly deleted or hollowed out into a heading with nothing under it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;marketplaceContract&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;contracts/marketplace.md&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;marketplaceContract&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="sr"&gt; Claim &lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="sr"&gt; Shipped source &lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="sr"&gt; Executable proof &lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;marketplaceContract&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sr"&gt;/exactly&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+500 characters/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;marketplaceContract&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sr"&gt;/bar or panel/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;marketplaceContract&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sr"&gt;/trust boundary/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;marketplaceContract&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sr"&gt;/hash-bound Buzz render receipt/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The commit touched &lt;code&gt;.harness-hash&lt;/code&gt; (+8/-7), &lt;code&gt;README.md&lt;/code&gt;, &lt;code&gt;contracts/marketplace.md&lt;/code&gt; (+18), &lt;code&gt;tests/RTM.md&lt;/code&gt;, and &lt;code&gt;tests/contract.test.js&lt;/code&gt; (+6). Small diff. It is the same move the audit was asking for, applied one layer earlier: state the requirement in a file, and make the test suite fail if the file stops saying it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two bugs where the proof machinery broke its own preconditions
&lt;/h2&gt;

&lt;p&gt;Both of these landed the same day, in the same fleet, and they are the same shape: the thing that verifies work was interfering with the work it verified.&lt;/p&gt;

&lt;h3&gt;
  
  
  A gate runner racing its own input
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;scripts/run-plugin-gates.sh&lt;/code&gt; in omarchy-docket-entry fed each gate a small JSON envelope through a pipe. A gate that exits before reading stdin races the producer into SIGPIPE, exit 141. So a deterministic invalid-verdict check became an intermittent gate crash, dependent on scheduling. Commit &lt;code&gt;240b2d6&lt;/code&gt; swaps the pipe for a here-string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;INPUT&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;jq &lt;span class="nt"&gt;-nc&lt;/span&gt; &lt;span class="nt"&gt;--arg&lt;/span&gt; c &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="s1"&gt;'{candidate:$c, action:"omarchy-submit", env:{repo:""}}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;gate &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$GATES&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;/c&lt;span class="k"&gt;*&lt;/span&gt;.sh&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="c"&gt;# Feed the small JSON envelope with a here-string. A pipe lets a gate that&lt;/span&gt;
  &lt;span class="c"&gt;# exits before reading stdin race the producer into SIGPIPE (141), turning a&lt;/span&gt;
  &lt;span class="c"&gt;# deterministic invalid-verdict check into an intermittent gate crash.&lt;/span&gt;
  &lt;span class="nv"&gt;verdict&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;bash &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$gate&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; 2&amp;gt;/dev/null &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$INPUT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="c"&gt;# A gate that emits nothing has crashed hard. Fail closed rather than&lt;/span&gt;
  &lt;span class="c"&gt;# silently counting it as clean, which is how a broken gate becomes theater.&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$verdict&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="c"&gt;# (excerpt: the loop goes on to print CRASH, set blocked=1, and continue)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fail-closed-on-empty branch and that comment about theater were already in the file. Somebody had already thought carefully about a gate emitting nothing. What was broken was that the runner could manufacture the empty verdict itself, and then correctly fail closed on a condition it had caused. This is the inverse of the audit's problem: there the evidence was missing, here the evidence was lying. A safety check firing on its own noise is still a false alarm, and false alarms are how people learn to ignore gates.&lt;/p&gt;

&lt;h3&gt;
  
  
  A render that dirtied the source it was proving
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;scripts/rig-render.sh&lt;/code&gt; in the template will only issue a render receipt if the source tree is clean, which is the entire point of a receipt: it binds an image to a specific source state. The glob of files whose modification marks the tree dirty included &lt;code&gt;preview.png&lt;/code&gt;, the render's own output.&lt;/p&gt;

&lt;p&gt;So a failed render left a stale &lt;code&gt;preview.png&lt;/code&gt; behind. That file marked the source dirty. No retry could ever produce a clean receipt. One bad render poisoned every attempt after it. Commit &lt;code&gt;52a9d42&lt;/code&gt; removes the artifact from the precondition: the pathspec used to carry &lt;code&gt;preview.png&lt;/code&gt; between &lt;code&gt;manifest.json bin&lt;/code&gt; and &lt;code&gt;README.md&lt;/code&gt;, and after the fix it reads:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;SOURCE_DIRTY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false
&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;$SOURCE_COMMIT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"unknown"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
   &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git &lt;span class="nt"&gt;-C&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; status &lt;span class="nt"&gt;--porcelain&lt;/span&gt; &lt;span class="nt"&gt;--untracked-files&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;all &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="s1"&gt;'*.qml'&lt;/span&gt; &lt;span class="s1"&gt;'*.js'&lt;/span&gt; manifest.json bin README.md assets/banner.svg &lt;span class="se"&gt;\&lt;/span&gt;
     e2e scripts/rig-render.sh 2&amp;gt;/dev/null&lt;span class="si"&gt;)&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="nv"&gt;SOURCE_DIRTY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true
&lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The obvious fix is to delete &lt;code&gt;preview.png&lt;/code&gt; at the top of every run. That fix is wrong, and the reason is worth stating. The receipt exists to distinguish a render of clean source from a render of dirty source. If the script scrubs the output first, every dirty-source failure gets laundered into a clean run and the distinction the receipt sells is gone. Removing the output from the precondition is a smaller change and it keeps the signal. The same class of fix landed in two other entries that day: "keep failed Capture renders retryable" in capture-conveyor (&lt;code&gt;04ca3ae&lt;/code&gt;) and "allow clean render retry after failed capture" in loose-ends (&lt;code&gt;88054b8&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  A dead-man that could not tell quiet from dead
&lt;/h2&gt;

&lt;p&gt;At 22:12 I asked for something unrelated: &lt;code&gt;i need ezekiel to start recievinf the emails like he does withe blog backfill skill that runs the blog work u know what i mean&lt;/code&gt;. Ezekiel does the social posting. The blog pipeline already emails him a per-post packet. The real-estate content machine behind comehomealabama.com, run out of coastal-realty-ops, had been soaking unattended for 11 days and it was time to point it at him too.&lt;/p&gt;

&lt;p&gt;Claude Fable 5 ran a health check before flipping anything, on the reasoning that Ezekiel should not start receiving packets from a broken producer and should not get 11 days of backlog dropped on him in one morning. The soak verdict: five posts landed on Aug 21, 24, 26, 28 and 31, all Monday/Wednesday/Friday, every prior post packeted, liveness green, and the ledger showed exactly one unsent packet. He would start with one email.&lt;/p&gt;

&lt;p&gt;The flip itself was five minutes and nine tool calls, shipped as coastal-realty-ops PR #50 (&lt;code&gt;17394b3&lt;/code&gt;): &lt;code&gt;packet.env&lt;/code&gt; &lt;code&gt;PACKET_TO&lt;/code&gt; set to &lt;code&gt;ezekiel@intentsolutions.io&lt;/code&gt; with me on CC. The file is sourced per run, so no restart, effective at the next 05:15 sweep. That commit also banked 5 lines of &lt;code&gt;decisions.jsonl&lt;/code&gt; and 3 lines of &lt;code&gt;topics-queue.jsonl&lt;/code&gt; the producer had accumulated during the soak.&lt;/p&gt;

&lt;p&gt;The health check is what found the bug. &lt;code&gt;scripts/journal/mandy-posting-packet.sh&lt;/code&gt; had three clean no-op exits (no ledger, no packets due, no digest week) and all three returned 0 without touching &lt;code&gt;mandy-posting-packet.ok&lt;/code&gt;. The estate dead-man sweep reads a fresh &lt;code&gt;.beat&lt;/code&gt; with a stale &lt;code&gt;.ok&lt;/code&gt; as running-but-failing. So a perfectly healthy pipeline with nothing due for two days would page. It was already visible in the wild: &lt;code&gt;.ok&lt;/code&gt; stuck at Aug 29 (the Aug 28 post's packet fired that morning) while &lt;code&gt;.beat&lt;/code&gt; kept advancing.&lt;/p&gt;

&lt;p&gt;The commit message for comehomealabama PR #8 (&lt;code&gt;d87bada&lt;/code&gt;) carries the rule in one line: a clean no-op IS a successful run. Change was +5/-3 in one shell script, verified with &lt;code&gt;shellcheck -S warning&lt;/code&gt;, &lt;code&gt;bash -n&lt;/code&gt;, and a live &lt;code&gt;--sweep&lt;/code&gt; against the current ledger that logged "no packets due" and refreshed &lt;code&gt;.ok&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The tempting shortcut is to touch &lt;code&gt;.ok&lt;/code&gt; at the top of the script and stop thinking about it. That reports healthy before doing any work, which is precisely the failure the dead-man exists to catch. The marker belongs on every path that legitimately completes, no-ops included, and on no path that does not. Quiet and dead have to be distinguishable, and the only place that distinction can live is in the script that knows which one it is.&lt;/p&gt;

&lt;p&gt;The part I keep coming back to: nothing was on fire. The two-day quiet window that would have false-paged had not happened yet. It got found because Claude Fable 5 checked the system before trusting it with a person's inbox.&lt;/p&gt;

&lt;h2&gt;
  
  
  Also shipped
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Retiring a carried patch in the Buzz fork.&lt;/strong&gt; &lt;code&gt;cb633a0c4&lt;/code&gt; plus PRs #30 and #31 emptied &lt;code&gt;CARRIED_PATCHES&lt;/code&gt; in &lt;code&gt;scripts/fork-gates/check-additive-only.sh&lt;/code&gt;, deleted the carried 311-line e2e spec &lt;code&gt;desktop/tests/e2e/manual-invite-join.spec.ts&lt;/code&gt;, replaced FORK.md's carried-patches exception with &lt;code&gt;None - empty by design&lt;/code&gt;, and filed a 131-line audit at &lt;code&gt;000-docs/009-AA-AUDR-fork-contract-breach-2026-08-16.md&lt;/code&gt;. PRs #26 and #27 had carried an invite-to-default-channel patch on fork main, the same class of fork-contract breach as the earlier PR #16 incident already documented in &lt;code&gt;000-docs/007&lt;/code&gt;. Production now runs the upstream published image (&lt;code&gt;ghcr.io/block/buzz@sha256:fe092cf9...&lt;/code&gt;), enrollment moved to an ops-side watcher in the private ops repo, and the real fix is tracked upstream as &lt;code&gt;block/buzz#4307&lt;/code&gt;. Merge-and-restore beat revert because the upstream sync supersedes the carry without rewriting history. Both &lt;code&gt;check-additive-only.sh&lt;/code&gt; and &lt;code&gt;check-must-survive.sh&lt;/code&gt; pass with &lt;code&gt;CARRIED_PATCHES&lt;/code&gt; empty, gate output pasted into the PR body. A large upstream sync (&lt;code&gt;91452d823&lt;/code&gt;) landed about 15 upstream commits the same day.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A discovery that ended in deliberate non-adoption.&lt;/strong&gt; Starting 02:10, Claude Fable 5 ran a discovery on the third-party &lt;code&gt;no-mistakes&lt;/code&gt; tool against the Intent Solutions testing SOP. It is a Go git-proxy: you push to a &lt;code&gt;no-mistakes&lt;/code&gt; remote instead of origin and it runs intent, rebase, review, test, docs, lint, push, PR and CI in an isolated disposable worktree, with an LLM review stage that falls back across agents and a CI repair loop with guarded force-push. We did not adopt it. What came out was &lt;code&gt;worktree-run.sh&lt;/code&gt; built into &lt;code&gt;audit-harness&lt;/code&gt;, a verification of the read-only-test rule, and the non-adoption recorded as a decision instead of an unwritten "we looked at it once". Two incidental findings: &lt;code&gt;yamllint&lt;/code&gt; was not installed on this box, and the escape-scan expectation was inverted, since the test expects a non-zero exit (a REFUSE) when policy is being weakened.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A $0 calendar stack, decided in conversation, no commits.&lt;/strong&gt; The one item of the day with neither a shipped source nor an executable proof, recorded here as the exception it is. With a Buzz VPS bill due the next day I asked what was free, then &lt;code&gt;im so confused whata the most texhnically sound optiin that would be most respected by underground linux users as my teams set up&lt;/code&gt;. Answer: Radicale on the VPS that already exists. One Python process, and the team calendar is a directory of plain &lt;code&gt;.ics&lt;/code&gt; text files you can grep and diff, backed up by borg like any other directory. khal plus vdirsyncer for the terminal, Cal.com's free tier for outward booking. The part worth recording is the refusal. Fastmail was rejected as a mail viewer, because a calendar decision should not quietly turn into a second mail migration one month after the MXroute cutover.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the day cost
&lt;/h2&gt;

&lt;p&gt;The session analyzer logged 19 failure-to-fix arcs and 2 course-corrections across four models (Claude Opus 5, Claude Sonnet 5, Claude Fable 5, GPT 5.6 Luna), over sessions spanning 1169 minutes of wall clock. GPT 5.6 Luna took &lt;code&gt;claude-code-plugins&lt;/code&gt; for 2 sessions, 187 turns, 361 minutes. Claude Fable 5 took &lt;code&gt;intent-eval-platform&lt;/code&gt; for 3 sessions, 27 turns, 8 errors and both course-corrections. Claude Opus 5 and Claude Fable 5 split the home layer across 3 sessions and 273 minutes with 9 errors. Claude Fable 5 did coastal-realty-ops in 5 minutes and 9 tool calls.&lt;/p&gt;

&lt;p&gt;The two ends of that range are the same instinct at different scales. GPT 5.6 Luna was told to finish the epics and spent six hours producing an audit that closed nothing, because closing them honestly was not on the menu. Claude Fable 5 was told to switch Ezekiel on, checked the pipeline's health first, and then did exactly what it was asked. Only one of the two delivered the literal request, and it delivered it last. Both started from the same place: find out whether the thing is true before writing down that it is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Posts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://startaitools.com/posts/a-green-result-only-covers-what-it-ran/" rel="noopener noreferrer"&gt;A green result only covers what it ran&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://startaitools.com/posts/scope-the-guard-to-what-the-job-writes/" rel="noopener noreferrer"&gt;Scope the guard to what the job writes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://startaitools.com/posts/one-corrected-check-fifteen-repos/" rel="noopener noreferrer"&gt;One corrected check, fifteen repos&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;{&lt;br&gt;
  "&lt;a class="mentioned-user" href="https://dev.to/context"&gt;@context&lt;/a&gt;": "&lt;a href="https://schema.org" rel="noopener noreferrer"&gt;https://schema.org&lt;/a&gt;",&lt;br&gt;
  "@type": "BlogPosting",&lt;br&gt;
  "headline": "Every Claim Needs a Shipped Source and an Executable Proof",&lt;br&gt;
  "description": "Every claim needs a shipped source and an executable proof. What a six-hour audit that closed nothing found out about code that was already finished.",&lt;br&gt;
  "url": "&lt;a href="https://startaitools.com/posts/working-is-not-proven/" rel="noopener noreferrer"&gt;https://startaitools.com/posts/working-is-not-proven/&lt;/a&gt;",&lt;br&gt;
  "datePublished": "2026-08-31T10:00:00-06:00",&lt;br&gt;
  "dateModified": "2026-08-31T10:00:00-06:00",&lt;br&gt;
  "author": {&lt;br&gt;
    "@type": "Person",&lt;br&gt;
    "name": "Jeremy Longshore"&lt;br&gt;
  },&lt;br&gt;
  "publisher": {&lt;br&gt;
    "@type": "Organization",&lt;br&gt;
    "name": "Start AI Tools",&lt;br&gt;
    "url": "&lt;a href="https://startaitools.com" rel="noopener noreferrer"&gt;https://startaitools.com&lt;/a&gt;"&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

</description>
      <category>testing</category>
      <category>cicd</category>
      <category>automation</category>
      <category>devops</category>
    </item>
    <item>
      <title>One Corrected Check, Fifteen Repos</title>
      <dc:creator>Jeremy Longshore</dc:creator>
      <pubDate>Tue, 01 Sep 2026 10:21:25 +0000</pubDate>
      <link>https://dev.to/jeremy_longshore/one-corrected-check-fifteen-repos-51gk</link>
      <guid>https://dev.to/jeremy_longshore/one-corrected-check-fifteen-repos-51gk</guid>
      <description>&lt;p&gt;Two gates failed the same way on 2026-08-30, in systems that share no code.&lt;/p&gt;

&lt;p&gt;The first checked whether a set of run fields were non-null. A recorded discovery run could therefore declare 3,000 skills while carrying 19 rows, and the boundary would pass it, because 3,000 is not null and 19 is not null. Runs 6 through 11 all disagreed with their own row counts. Run 11 declared 3,069 against 3,678 actual rows.&lt;/p&gt;

&lt;p&gt;The second checked whether a marketplace submission description was exactly 500 characters. Which 500 characters was never asked. So 500 characters of filler passed, and 500 characters of filler is precisely the submission the gate was written to stop.&lt;/p&gt;

&lt;p&gt;A check measuring a proxy instead of the property is the house failure mode on this blog and has been for months. I am not going to pretend it was a discovery. What was actually expensive on this day was not diagnosing either gate. It was pushing one corrected gate through fifteen repos that carry it as a vendored, hash-pinned copy rather than importing it. That half is the post.&lt;/p&gt;

&lt;h2&gt;
  
  
  The evidence boundary that could not see its own run
&lt;/h2&gt;

&lt;p&gt;Epic 5, "Coherent Freshie Evidence," closed in &lt;code&gt;claude-code-plugins&lt;/code&gt; that day. The closure AAR is &lt;code&gt;000-docs/809-AA-AACR-epic-5-closure.md&lt;/code&gt;, 134 lines, filed against epic bead &lt;code&gt;claude-h05s&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The AAR states the defect in one line: "The old boundary checked whether required run fields were non-null, not whether the header and its rows described the same run." The run-6 shape is the image that sticks. Three thousand declared skills, nineteen rows, green.&lt;/p&gt;

&lt;p&gt;Five invariants replaced it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;gate_run_completeness()&lt;/code&gt; compares the run header against same-run rows before any export work begins.&lt;/li&gt;
&lt;li&gt;The grade histogram, CSV row count, CSV hash, run tag, and immutable Dolt commit must identify one export, not adjacent runs that happen to be close.&lt;/li&gt;
&lt;li&gt;Behavioral-evaluation identity is &lt;code&gt;jrig_run_id&lt;/code&gt;, held separate from discovery-run identity.&lt;/li&gt;
&lt;li&gt;Evidence class and retention are validity conditions, not annotations. Three legacy proofs are now honestly classified E0. No public verified projection remains.&lt;/li&gt;
&lt;li&gt;Blocking CI installs a pinned Dolt binary immediately before an exact guarded runner, which must execute one real hermetic cycle with zero skips against scratch SQLite, Dolt, and filesystem state, then prove live-server refusal.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Nine commits landed that sequence, and read as a run they are a reviewer finding bypasses faster than they could be closed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;make exit evidence fail closed
reject skipped and overwritten proofs
close generator and overwrite bypasses
require executed hermetic proof
bind proof method and install order
verify guarded cycle invocation
bind receipts and harden hermetic proof
publish reproducible run 14 receipts
enforce graded corpus parity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The independent boundary review returned PASS only "after reproducing and closing skipped tests, generator no-op, lifecycle replacement, aliased mutation, and post-verification binary-overwrite attacks." Five attacks. Each one maps onto a commit in that list. &lt;code&gt;reject skipped and overwritten proofs&lt;/code&gt; is the skipped-test attack. &lt;code&gt;close generator and overwrite bypasses&lt;/code&gt; is the generator no-op. &lt;code&gt;bind proof method and install order&lt;/code&gt; is what stops the binary being swapped after verification. The commit log is not a changelog here, it is an attack transcript with the reviewer's half missing.&lt;/p&gt;

&lt;p&gt;The first commit alone touched 8 files for +1515/-256, including &lt;code&gt;run-delta.py&lt;/code&gt; at +247/-50, &lt;code&gt;measure-epic-1-scorecard.mjs&lt;/code&gt; at +382, and four test files. All nine commit bodies were empty, which is worth one dry line: the sequence that produced the most legible story of the day carried no explanation with it at all.&lt;/p&gt;

&lt;p&gt;Final receipts. Run 14 declared 3,053 against 3,053 rows, delta 0. 3,630 compliance rows against 3,630 grade rows with matching SHA-256. Run 14 is bound to immutable Dolt commit &lt;code&gt;2ljhn79ge74uj1kd7q2chqgo9ne0tulb&lt;/code&gt;, grade CSV SHA-256 &lt;code&gt;72fbb289e8451d9a4bbe95cae0b9a1797588c0197589f94ddd1cde48241e4ef0&lt;/code&gt;, histogram A 1,872 / B 1,117 / C 479 / D 157 / F 5. &lt;code&gt;pnpm run measure:e1:check&lt;/code&gt; passed 39 measurement tests and the tracked artifact matched its exact regeneration from the Git index. PR #1387 merged as &lt;code&gt;78e3580c&lt;/code&gt; after 34 reporting checks with zero failures.&lt;/p&gt;

&lt;p&gt;The AAR's own first lesson is the one to keep:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A green test command is not proof that the governed body ran. Exact test count, zero skips, and a guarded method invocation are part of the boundary now.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Its second lesson is quieter and I think better: "Zero E2/E3 claims is a safe state, not a 100% retention measurement." The scorecard now reports &lt;code&gt;retention_percent&lt;/code&gt; as &lt;code&gt;null&lt;/code&gt;. A tool with nothing to measure says nothing rather than reporting a flattering 100%.&lt;/p&gt;

&lt;h2&gt;
  
  
  Five hundred characters of anything
&lt;/h2&gt;

&lt;p&gt;The second gate is &lt;code&gt;scripts/gates/c43-omarchy-marketplace-presentation.sh&lt;/code&gt;, which guards marketplace submission copy across the Omarchy widget fleet. Here is what it checked:&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="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;$HAS_BAR_WIDGET&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"true"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BAR_DESC_LENGTH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s2"&gt;"500"&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;FINDINGS+&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="s2"&gt;"barWidget description uses &lt;/span&gt;&lt;span class="nv"&gt;$BAR_DESC_LENGTH&lt;/span&gt;&lt;span class="s2"&gt;/500 characters"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Length equality, and nothing else. A submission had to fill its allowance exactly, and filling an allowance is trivially satisfied by padding.&lt;/p&gt;

&lt;p&gt;The comment written above the replacement checks is the whole day in five lines:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Length alone is not copy quality. A submission description must identify the product, explain what the user can see or do, and state a meaningful trust boundary. These checks deliberately reject generic 500-character filler while repo-specific contract tests pin the precise claims each plugin is allowed to make.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The new checks run as an embedded &lt;code&gt;python3&lt;/code&gt; heredoc inside the bash gate, each one appending to a findings list rather than exiting early, so a bad description gets told everything wrong with it at once. Four of them, excerpted:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;sentences&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;part&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;part&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;(?&amp;lt;=[.!?])\s+&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;part&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sentences&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;findings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description needs at least four readable sentences&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;sentences&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sentences&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;findings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;opening sentence is too thin to establish the user outcome&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;surface_terms&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bar&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;panel&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pill&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;widget&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;rf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;\b&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;term&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;\b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;term&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;surface_terms&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;findings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description never explains the visible bar, panel, pill, or widget&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two more term lists do the load-bearing work. An interaction list (&lt;code&gt;open&lt;/code&gt;, &lt;code&gt;click&lt;/code&gt;, &lt;code&gt;select&lt;/code&gt;, &lt;code&gt;copy&lt;/code&gt;, &lt;code&gt;install&lt;/code&gt;, &lt;code&gt;focus&lt;/code&gt;, &lt;code&gt;refresh&lt;/code&gt;, &lt;code&gt;preview&lt;/code&gt;, &lt;code&gt;sort&lt;/code&gt;, &lt;code&gt;scan&lt;/code&gt;, and about a dozen more) fails a description that "gives no concrete user interaction or visible behavior." A boundary list (&lt;code&gt;no&lt;/code&gt;, &lt;code&gt;never&lt;/code&gt;, &lt;code&gt;only&lt;/code&gt;, &lt;code&gt;without&lt;/code&gt;, &lt;code&gt;offline&lt;/code&gt;, &lt;code&gt;local&lt;/code&gt;, &lt;code&gt;private&lt;/code&gt;, &lt;code&gt;fixed&lt;/code&gt;) fails one that "gives no privacy, network, data, or write boundary." A description can be four fluent sentences about nothing and still fail both.&lt;/p&gt;

&lt;p&gt;Then there is a banned-phrase list inside the gate, nine entries: &lt;code&gt;cutting-edge&lt;/code&gt;, &lt;code&gt;game-changer&lt;/code&gt;, &lt;code&gt;game-changing&lt;/code&gt;, &lt;code&gt;revolutionary&lt;/code&gt;, &lt;code&gt;supercharge&lt;/code&gt;, &lt;code&gt;seamless&lt;/code&gt;, &lt;code&gt;robust solution&lt;/code&gt;, &lt;code&gt;unlock your&lt;/code&gt;, &lt;code&gt;take your productivity to the next level&lt;/code&gt;. I run the same instrument against this blog's prose from a JSON deny-list, and the overlap is not coincidence. Both lists exist because the same generator produces both kinds of copy.&lt;/p&gt;

&lt;p&gt;Plus one cross-field check with the best failure message in the set: &lt;code&gt;manifest and barWidget descriptions tell different product stories&lt;/code&gt;, which fires when the two description fields disagree about what the thing is.&lt;/p&gt;

&lt;p&gt;None of that is clever, and it is worth being honest about what it does not do. A length check and a shape check are the same class of instrument, and a determined author can pad four sentences as easily as one. The gate is not proving quality. It raises the floor from "any 500 bytes" to "500 bytes that name the product, show a visible surface, describe an interaction, and state a boundary," and its own comment says where the real work goes: repo-specific contract tests pin the precise claims each plugin is allowed to make.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part that actually cost the day
&lt;/h2&gt;

&lt;p&gt;Downstream repos do not import this gate. Each one carries a vendored copy. The lane is declared at &lt;code&gt;scripts/gates/.lane-manifest&lt;/code&gt;, whose header reads:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Vendored gate lane. Regenerate with scripts/sync-gate-lane.sh, never hand-edit.
# canonical: contributing-clanker@359a27cde21e60086f95a3ddee99c8920a3d7ca2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That header is quoted with its dash normalized to a comma, because the real file uses an em dash and this blog's own lint gate would quarantine the post for reproducing it.&lt;/p&gt;

&lt;p&gt;Below the header sit per-file SHA-256 hashes of every gate script. Alongside it, each repo carries &lt;code&gt;.harness-hash&lt;/code&gt; covering the wider audited surface: &lt;code&gt;contract.test.js&lt;/code&gt;, &lt;code&gt;run-plugin-gates.sh&lt;/code&gt;, &lt;code&gt;stryker.config.json&lt;/code&gt;, &lt;code&gt;tests/RTM.md&lt;/code&gt;, &lt;code&gt;tests/TESTING.md&lt;/code&gt;, and the rest.&lt;/p&gt;

&lt;p&gt;So the corrected conditional is not a one-line edit. The canonical pin moved from &lt;code&gt;contributing-clanker@359a27cd&lt;/code&gt; to &lt;code&gt;@81239c6e&lt;/code&gt;, and in every consuming repo four hashes had to move together:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the lane manifest hash, in &lt;code&gt;.lane-manifest&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;the &lt;code&gt;c43&lt;/code&gt; gate hash, in both &lt;code&gt;.lane-manifest&lt;/code&gt; and &lt;code&gt;.harness-hash&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;run-plugin-gates.sh&lt;/code&gt;, because the gate list it dispatches changed&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;contract.test.js&lt;/code&gt;, because the per-repo contract test that pins the allowed claims changed with the copy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The third and fourth entries are the ones that make this expensive. The gate file itself is one hash. But correcting the gate changed which checks run, so the runner's hash moved, and tightening the copy to satisfy the gate changed each repo's contract test, so that hash moved too. One upstream edit fans out into four hashes per repo, and any repo where they drift fails its own harness verification before it fails the gate. That is the design working, and it is also the bill.&lt;/p&gt;

&lt;p&gt;Here is the shape of a single downstream repo's day, using &lt;code&gt;omarchy-listening-post-entry&lt;/code&gt;, which took four commits:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fix: complete Listening Post marketplace copy
test: pin Listening Post marketplace story
test: enforce marketplace presentation quality
chore: repin audit harness artifacts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read that in order and it is the whole propagation protocol in four steps. Rewrite the copy so the new gate passes. Pin the specific claims this plugin is allowed to make, in its own contract test. Take the corrected gate from the lane. Re-pin the harness hashes so the repo verifies against its new self. Every repo ran some subset of exactly that. The spread runs from four commits down to one: &lt;code&gt;omarchy-foundry-entry&lt;/code&gt; took a single &lt;code&gt;test:&lt;/code&gt; commit and no copy commit at all, which is what it looks like when only the gate underneath a repo moves.&lt;/p&gt;

&lt;p&gt;Fifteen entry repos took the change: bazaar, capture-conveyor, crew-chief, desk-transition, docket, flow-boundary, foundry, listening-post, loose-ends, mlb-booth, pit-wall, quiet-queue, wait-state, workspace-storyboard, x-files. Twelve of them needed a &lt;code&gt;fix: complete &amp;lt;Name&amp;gt; marketplace copy&lt;/code&gt;. The other three, desk-transition, foundry, and wait-state, needed only the proof and the re-pin. Counting the template and the canonical lane source itself, the fan-out ran to 48 commits across 17 repos. The whole day, including the freshie epic, came to 112 commits across 19 repos.&lt;/p&gt;

&lt;p&gt;The tradeoff is deliberate and I would still take it. Vendoring plus hash pinning means a downstream repo cannot silently run a gate that differs from canonical, and cannot quietly weaken one either. What it buys in tamper-evidence it charges in propagation, and the charge is not proportional to the size of the fix. A one-character change and a rewrite cost the same fifteen-repo sweep, because the sweep is the unit of work, not the edit. The implication is that batching discipline matters more than edit discipline on a lane like this one, though that follows from the design rather than from anything measured on this particular day: both corrected gates here lived in unrelated systems, so nothing rode the same sweep.&lt;/p&gt;

&lt;h2&gt;
  
  
  The gate that forced an honesty edit
&lt;/h2&gt;

&lt;p&gt;Twelve repos needed a copy commit, and four of them needed a second pass after it. Those four are the interesting ones, because the gate did not extract more words from them on the second pass, it extracted truer ones:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fix: state MLB Booth data boundary honestly
fix: clarify Loose Ends queue priority
fix: make Bazaar marketplace copy precise
fix: tighten Pit Wall marketplace copy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The template's own description went the same direction. One long run-on became shorter sentences. "real-shell screenshot evidence" was softened to "shell screenshot evidence." "plugin-specific SVG banner" became "product-specific SVG banner." A gate asking for four readable sentences and a stated trust boundary got four readable sentences, and the claims came out weaker and truer than they went in. That was not designed. It falls out of asking for a trust boundary at all, because you cannot state one without noticing where yours actually sits.&lt;/p&gt;

&lt;h2&gt;
  
  
  A watch that could only see page one
&lt;/h2&gt;

&lt;p&gt;Third thread, and it stays short because it is the same defect wearing different clothes. In &lt;code&gt;intent-os&lt;/code&gt;, bead &lt;code&gt;spine-lkb.12&lt;/code&gt; and PR #566 shipped &lt;code&gt;ops/plane-invite-watch/&lt;/code&gt;, a daily VPS timer that reconciles the Plane workspace invitation list against members and against its own known state, paging Buzz sys-incidents when an invitation is queued with no mail behind it, sits unclaimed past 7 days, or belongs to somebody who is already a member.&lt;/p&gt;

&lt;p&gt;Two details earn its place. Its &lt;code&gt;automations.md&lt;/code&gt; row is marked &lt;code&gt;NOT-YET-ARMED until deploy receipts&lt;/code&gt;, which is the same call as reporting &lt;code&gt;retention_percent&lt;/code&gt; as &lt;code&gt;null&lt;/code&gt;: a row describing a timer nobody has armed yet is a lie in a document people trust. And the review caught that both fetches read only the first page, because "a watch reading only page one would go blind past 100 rows," rated HIGH. Cursor and envelope pagination went in, hermetic drill 9/9 after the change, full &lt;code&gt;pnpm check&lt;/code&gt; green.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three sessions, one steer
&lt;/h2&gt;

&lt;p&gt;Three sessions ran concurrently, and the split is worth one line because it was not arbitrary. The fan-out work ran on Claude Opus 5 with Claude Opus 4.8 alongside it, 754 turns and 171 tool calls across twelve hours, because fifteen near-identical repos is exactly the job where a model holding a long invariant beats a fast one. The &lt;code&gt;intent-os&lt;/code&gt; watcher ran on Claude Fable 5, 443 turns and zero errors in about an hour.&lt;/p&gt;

&lt;p&gt;One steer is worth quoting exactly as typed, because it is the day's thesis arriving as a correction and it arrived before I had written any of the above:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;yes add the auto-stash guard that seems like a band daid whats root cause fix&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The model had proposed the thing that makes the symptom go away. The correction was not "that code is wrong," it was "that is the wrong layer." Same shape as the two gates: a check that satisfies the condition in front of it without touching the property underneath. Other steers that day were shorter and in the same register: "rm -rf the decoy dirs," "verify the card shows up on ezekiels board," "and what did u decide ?"&lt;/p&gt;

&lt;h2&gt;
  
  
  What the day bought
&lt;/h2&gt;

&lt;p&gt;Two gates that now measure the property instead of a stand-in for it, and one monitor that can see past its first page. That is the cheap half.&lt;/p&gt;

&lt;p&gt;The expensive half is the fifteen repos, and what it bought there was a fleet where no consuming repo can run a gate that quietly differs from canonical. The cost of that guarantee is that every correction, however small, is a fifteen-repo sweep with four hashes moving in lockstep per repo. Forty-eight commits to move one conditional is not overhead I would call waste. It is the price of the tamper-evidence, stated in full, which is the number that belongs next to the guarantee whenever the next lane gets vendored.&lt;/p&gt;

&lt;h2&gt;
  
  
  Also shipped
&lt;/h2&gt;

&lt;p&gt;An adversarial multi-seat council ran that evening against a proposed company-calendar stack for the estate, reviewing it through fault-tolerance, data-model and source-of-truth, and convention-over-configuration lenses. Separately, an external tool called "no-mistakes" (a Go git-proxy that runs an intent, review, test, docs, lint, push, PR, CI pipeline inside an isolated worktree) was evaluated against the in-house audit-harness.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Posts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/blog/the-skip-that-counted-as-a-pass/"&gt;The Skip That Counted as a Pass&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/blog/a-green-result-only-covers-what-it-ran/"&gt;A Green Result Only Covers What It Ran&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/blog/scope-the-guard-to-what-the-job-writes/"&gt;Scope the Guard to What the Job Actually Writes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>cicd</category>
      <category>qualitygates</category>
      <category>governance</category>
      <category>testing</category>
    </item>
    <item>
      <title>Scope the Guard to What the Job Actually Writes</title>
      <dc:creator>Jeremy Longshore</dc:creator>
      <pubDate>Mon, 31 Aug 2026 10:18:23 +0000</pubDate>
      <link>https://dev.to/jeremy_longshore/scope-the-guard-to-what-the-job-actually-writes-12k8</link>
      <guid>https://dev.to/jeremy_longshore/scope-the-guard-to-what-the-job-actually-writes-12k8</guid>
      <description>&lt;p&gt;Two systems mismeasured what was in front of them. One aborted loudly on dirt that could not touch it. One returned a 200 and assigned the card to nobody. Both fixes narrowed what a piece of code claimed authority over.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 04:00 producer that aborted on dirt it would never touch
&lt;/h2&gt;

&lt;p&gt;The blog pipeline runs unattended every morning at 04:00, on the same working tree that every interactive Claude Code session uses. One bash function, &lt;code&gt;preflight_branch_normalize()&lt;/code&gt; in &lt;code&gt;scripts/blog/lib-cron-common.sh&lt;/code&gt;, is the guard that decides whether the run may proceed at all.&lt;/p&gt;

&lt;p&gt;It refused to run on ANY uncommitted tracked file. Full stop. A legitimate edit left unsaved overnight took down the entire cron job.&lt;/p&gt;

&lt;p&gt;This happened three times:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2026-08-13: persona files&lt;/li&gt;
&lt;li&gt;2026-08-18: a lost image-push race condition that left the tree diverged&lt;/li&gt;
&lt;li&gt;2026-08-29: uncommitted 68-insertion doc update to &lt;code&gt;000-docs/002-REF-omarchy-plugin-promotion-reference.md&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two of the three were the same cascade: the dirty-tree check FATAL'd, no post got produced, and the 05:00 posting packet had nothing to send to Ezekiel. The 08-18 abort came one step later in the same function, where an ff-only pull correctly refused a tree that a lost image-push race had diverged. That one was fixed at the push, not here, and the scoping change would not have saved it. The morning of the 29th the recovery was manual: commit the legitimate content, push, re-run backfill for the 28th by hand.&lt;/p&gt;

&lt;p&gt;The issue is mechanical: a human editor can legitimately leave work uncommitted while a nightly job wants to proceed. These are not in conflict. The job writes to four specific paths. Uncommitted changes anywhere else do not touch what the job produces.&lt;/p&gt;

&lt;h3&gt;
  
  
  The fix
&lt;/h3&gt;

&lt;p&gt;Commit &lt;code&gt;605835ec&lt;/code&gt;: &lt;code&gt;scripts/blog/lib-cron-common.sh&lt;/code&gt; (+28/-12). The preflight now FATALs only on uncommitted changes to the pipeline's own write-set:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;content/posts/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.blog-staging/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.claude/skills/blog-backfill/methodology/decisions.jsonl&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;static/images/posts/&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Uncommitted changes anywhere else are logged and left exactly where they are. The run proceeds.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why not the obvious approaches
&lt;/h3&gt;

&lt;p&gt;Two alternatives were considered and rejected.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Auto-stash:&lt;/strong&gt; A band-aid. It moves someone's active mid-edit work out from under them, and then pops the change back to uncommitted. The same file re-triggers the abort the next night. Auto-stash also touches work that is not the pipeline's business to touch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A retry loop or nightly re-run:&lt;/strong&gt; The wrong tool for this shape of failure. A dirty tree is a standing condition, not a transient one. It stays dirty at 04:15, 04:30, any time you retry. Retries just multiply the failure alerts instead of fixing anything.&lt;/p&gt;

&lt;p&gt;Scoping is the real fix. The producer genuinely cannot collide with dirt outside its write-set, so it should stop caring about it. The hazard is preserved: a half-written post in &lt;code&gt;content/posts/&lt;/code&gt; or a mid-edit &lt;code&gt;decisions.jsonl&lt;/code&gt; still aborts, because building on top of those is genuinely unsafe. That distinction is the whole reason this works.&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;# Abridged from preflight_branch_normalize(); log strings shortened.&lt;/span&gt;
&lt;span class="c"&gt;# Dirt inside the write-set still aborts. Dirt outside it is logged and left alone.&lt;/span&gt;
&lt;span class="nv"&gt;_porcelain&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git status &lt;span class="nt"&gt;--porcelain&lt;/span&gt; &lt;span class="nt"&gt;--untracked-files&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;no 2&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&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="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$_porcelain&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="nv"&gt;_dangerous&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&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="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$_porcelain&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'^.. (content/posts/|\.blog-staging/|static/images/posts/|\.claude/skills/blog-backfill/methodology/decisions\.jsonl)'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&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="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$_dangerous&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;_log &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$log_file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"FATAL: uncommitted changes to the pipeline's own files on '&lt;/span&gt;&lt;span class="nv"&gt;$current_branch&lt;/span&gt;&lt;span class="s2"&gt;', refusing to proceed"&lt;/span&gt;
    _log &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$log_file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"       These paths are what the producer writes; a half-finished post or edit here is unsafe to build on. Resolve and re-run:"&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="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$_dangerous&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$log_file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; 2&amp;gt;&amp;amp;1
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
  &lt;span class="k"&gt;fi
  &lt;/span&gt;&lt;span class="nv"&gt;_benign&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&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="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$_porcelain&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
  _log &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$log_file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"Pre-flight: &lt;/span&gt;&lt;span class="nv"&gt;$_benign&lt;/span&gt;&lt;span class="s2"&gt; uncommitted file(s) outside the pipeline write-set, ignoring, they will not be touched"&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The verification: a harness over four cases on a throwaway repo. It exercises two of the four write-set paths directly; the other two share the same match arm.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Benign &lt;code&gt;000-docs&lt;/code&gt; edit: passes the dirty check, logged as "ignoring, will not be touched"&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;content/posts/&lt;/code&gt; edit: FATAL&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;decisions.jsonl&lt;/code&gt; edit: FATAL&lt;/li&gt;
&lt;li&gt;Clean tree: passes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That morning's exact failure would now proceed untouched.&lt;/p&gt;

&lt;h2&gt;
  
  
  The alarm working is not the system working
&lt;/h2&gt;

&lt;p&gt;One more thing about how the morning started. The failure did not surface because someone noticed a missing post. It surfaced because a gap detector built ten days earlier caught the gap and paged with a loud "no post landed" subject instead of reporting healthy.&lt;/p&gt;

&lt;p&gt;That detector only existed for the third failure, and the reason it exists is the second one. On 2026-08-18 the producer aborted at 04:00 and the 05:00 heartbeat still called the pipeline healthy an hour later. The detector was built on 2026-08-19 precisely because detection had failed. So on 2026-08-29 it fired correctly, which is the system improving.&lt;/p&gt;

&lt;p&gt;It is still worth saying plainly that it could have gone on firing correctly indefinitely without anything getting better. Three runs failed inside seventeen days. The alarm got fixed after the second. The guard behind it stayed wrong through all three. An alarm that fires reliably on a recurring failure is a reason to go fix the cause, not evidence that the cause is handled.&lt;/p&gt;

&lt;h2&gt;
  
  
  The task board that returned HTTP 200 and assigned nobody
&lt;/h2&gt;

&lt;p&gt;Ezekiel gets the posting packet as an email at 05:00. For weeks, "done" meant "reply to the email with the URLs," and a 07:30 ingest job read those replies. But the ingest kept coming back empty.&lt;/p&gt;

&lt;p&gt;The problem with reply-as-completion: a missing reply is indistinguishable from a missing post.&lt;/p&gt;

&lt;p&gt;The fix (commit &lt;code&gt;add88e64&lt;/code&gt;): after the packet email sends and marks &lt;code&gt;packet_sent&lt;/code&gt;, the sweep also creates or updates one Plane card per post, assigned to Ezekiel. He drags it To Do to Done as he posts. A card has a state on a board. Email is the delivery; the card is the record.&lt;/p&gt;

&lt;p&gt;The failure direction matters: the card call runs after the email send and after &lt;code&gt;mark_sent&lt;/code&gt;, and it swallows every error. A Plane outage can never turn a delivered packet into a failed run.&lt;/p&gt;

&lt;h3&gt;
  
  
  The root cause
&lt;/h3&gt;

&lt;p&gt;Plane silently drops an assignee who is not a member of the destination project, as opposed to the workspace. The PATCH returns HTTP 200 even when the assignment fails. Ezekiel was a workspace member but had never been added to the CONTENT project, so every assign returned 200 and assigned nobody.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ensure_project_member&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Plane silently drops an assignee who is not a member of the PROJECT (not
    just the workspace). Idempotently add him so the assignment can actually
    stick. Returns True if he is (now) a member.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;member_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;member&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/projects/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;CONTENT_PROJECT&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/members/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;results&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;uid&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;member_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;[])]:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
        &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;POST&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/projects/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;CONTENT_PROJECT&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/members/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;member&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="c1"&gt;# 200/201 = added; 400 typically means "already a member", also fine.
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is why nine Omarchy showcase cards created on 2026-08-25 all read &lt;code&gt;assignees: []&lt;/code&gt; even though the assign job logged "assigned 9". That is why his Plane board showed no work to do.&lt;/p&gt;

&lt;p&gt;I isolated it by assigning a known-good member instead: Jeremy, a workspace admin. That worked instantly. Assign Ezekiel and it silently no-ops. Same code path, same 200. The difference was project membership.&lt;/p&gt;

&lt;p&gt;I fixed it two ways. Added Ezekiel to the CONTENT project and back-assigned all 10 existing cards, the nine broken Omarchy cards plus the one for that day's post. Then &lt;code&gt;blog-plane-card.py&lt;/code&gt; now calls &lt;code&gt;ensure_project_member&lt;/code&gt; idempotent on every run, so this cannot silently recur.&lt;/p&gt;

&lt;p&gt;One more Plane API quirk: assignees must be set in their own dedicated PATCH. Plane ignores an &lt;code&gt;assignees&lt;/code&gt; field mixed into a create or update payload.&lt;/p&gt;

&lt;p&gt;Verification: card created for the live post (HTTP 201). Re-run updates instead of duplicates (still exactly 1 card). Assignment confirmed by read-back. All 10 content cards now read &lt;code&gt;assignees=[ezekiel]&lt;/code&gt;. Clean end-to-end run prints "updated card ... (HTTP 200)" with no error note.&lt;/p&gt;

&lt;h2&gt;
  
  
  The correction that shrank the design
&lt;/h2&gt;

&lt;p&gt;The Plane card did not start out as one line in an existing job. The first pass at it was a tracking subsystem: a new state file, an ingest reconciler, its own cron entry.&lt;/p&gt;

&lt;p&gt;The correction came in voice dictation, so the transcript caught it garbled: "please dont make it comicates alproach it with simixty also." Cleaned up, that is "don't make it complicated, approach it with simplicity."&lt;/p&gt;

&lt;p&gt;What survived the correction was one sentence: add one step to the 05:00 packet job, so when Ezekiel gets his email he also gets a Plane card. Nothing else changes. The email stays. No new cron entry, no reconciler, no new state file.&lt;/p&gt;

&lt;p&gt;That is what shipped. Commit &lt;code&gt;add88e64&lt;/code&gt; is 17 changed lines in &lt;code&gt;blog-posting-packet.sh&lt;/code&gt; plus a 194-line &lt;code&gt;blog-plane-card.py&lt;/code&gt;. The rejected design would have added a fourth moving part to a pipeline whose whole problem that morning was that its existing parts were too entangled with each other.&lt;/p&gt;

&lt;p&gt;Worth being precise about what the models did here, because it was four of them across one long day. &lt;code&gt;Claude Opus 4.8&lt;/code&gt; and &lt;code&gt;Claude Opus 5&lt;/code&gt; carried the blog pipeline thread, including the preflight diagnosis and the scoping fix. &lt;code&gt;Claude Sonnet 5&lt;/code&gt; picked up shorter turns in the same tree. &lt;code&gt;Claude Fable 5&lt;/code&gt; ran the parallel Buzz investigation, which is where most of the day's errors landed: 34 of them across 847 minutes, against production Postgres auth logs over SSH. Across every session the day logged 474 tool calls, 40 failure-to-fix arcs, and 3 course-corrections in a 1112 minute span.&lt;/p&gt;

&lt;p&gt;The three corrections are the part worth keeping. None of them were "that code is wrong." All three were scope corrections: fold this into what already exists, go verify the thing actually ran, make it smaller. The elaborate version got built competently on the first pass. What it did not get was a check on whether the problem deserved that much machinery, and on this day that check is the only thing that kept a task board from becoming a subsystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  The through-line
&lt;/h2&gt;

&lt;p&gt;Both fixes narrow what a piece of code claims authority over. The preflight claimed authority over the whole working tree when it only writes four paths. The assign call treated a 200 as proof the assignment happened, when all the 200 actually confirmed was that the request had been accepted.&lt;/p&gt;

&lt;p&gt;The Plane fix did not literally remove code. It added a membership check and a second PATCH. What it narrowed was the claim: the assign call stopped treating an accepted request as a completed one. In both cases the code asserted something it did not govern, and the fix was to make the claim match the control.&lt;/p&gt;

&lt;h2&gt;
  
  
  Also shipped
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Omarchy marketplace submission sweep.&lt;/strong&gt; Eleven widget entry repos plus the shared template: Capture Conveyor, Desk Transition, Docket, Flow Boundary, Crew Chief, Foundry, Workspace Storyboard, Wait State, Quiet Queue, Listening Post, Loose Ends. The commit subjects run to "marketplace-ready" and "production certified", which is the repos' own shorthand and worth deflating here: what was actually established is that each widget loaded in a fresh Omarchy shell on the Buzz rig, with render receipts bound to the raw shell logs and runtime evidence kept separate from visual evidence. Submission is a filing, not an approval. That was breadth rather than depth, and it is not what made the day interesting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gate C43, the Omarchy marketplace presentation guard.&lt;/strong&gt; Landed at 16:38 as 163 lines plus a 119-line bats suite, wired into CI, then tightened four more times the same day: 16:45, 17:41, 18:08, and 20:36. Each tightening closed something the previous version had let through. It checks that a manifest description uses the full 500-character allowance the catalog schema permits, that a bar widget description matches it rather than telling a different product story, and that the copy names the product, says what the user can see or do, and states a trust boundary. Requiring the full allowance is an unusual rule, and the reason given in the gate is blunt: every short description that escaped was generic. Five revisions in four hours is its own small lesson about writing gates, and it deserves its own post rather than a paragraph here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hermes trust boundaries hardened in &lt;code&gt;claude-code-plugins&lt;/code&gt; (PR 1383).&lt;/strong&gt; Split the contribute skill into read-only, prepare, and publish surfaces, dropped the automatic install-persistence hooks, and required explicit state and workspace paths. Merged.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Buzz forensics, unresolved.&lt;/strong&gt; A separate thread that started as "save my automations and plan a clean reinstall" turned into reading production Postgres auth logs over SSH, per-pubkey auth successes and full connection lifecycles. It did not resolve into a shipped fix that day.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Posts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://startaitools.com/posts/every-safety-gate-has-a-failure-direction/" rel="noopener noreferrer"&gt;Every Safety Gate Has a Failure Direction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/blog/a-green-result-only-covers-what-it-ran/"&gt;A Green Result Only Covers What It Ran&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://startaitools.com/posts/gate-the-statement-not-the-tool-name/" rel="noopener noreferrer"&gt;Gate the Statement, Not the Tool Name&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>automation</category>
      <category>devops</category>
      <category>debugging</category>
      <category>cicd</category>
    </item>
  </channel>
</rss>
