<?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: imokokok</title>
    <description>The latest articles on DEV Community by imokokok (@imokokok).</description>
    <link>https://dev.to/imokokok</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%2F4135533%2Fc97dc514-9aa3-4e31-88de-456b265f8216.jpg</url>
      <title>DEV Community: imokokok</title>
      <link>https://dev.to/imokokok</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/imokokok"/>
    <language>en</language>
    <item>
      <title>Confirmations Are a Policy Threshold, Not a Finality Guarantee</title>
      <dc:creator>imokokok</dc:creator>
      <pubDate>Mon, 12 Oct 2026 07:31:12 +0000</pubDate>
      <link>https://dev.to/imokokok/confirmations-are-a-policy-threshold-not-a-finality-guarantee-2egg</link>
      <guid>https://dev.to/imokokok/confirmations-are-a-policy-threshold-not-a-finality-guarantee-2egg</guid>
      <description>&lt;p&gt;A transaction reaches 12 confirmations. Can a reviewer call it final?&lt;/p&gt;

&lt;p&gt;Only if the system defined what “final” means and recorded evidence for that claim.&lt;/p&gt;

&lt;h2&gt;
  
  
  A confirmation count answers one question
&lt;/h2&gt;

&lt;p&gt;A confirmation floor tells us how many blocks have been built on top of an inclusion. It is a useful policy threshold, but it is not a universal statement about consensus finality.&lt;/p&gt;

&lt;p&gt;The requirement should be part of the signed intent, before execution. For example:&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;"constraints"&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;"minConfirmations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"maxToleratedReorgDepth"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"finalityRequirement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"RPC_FINALIZED"&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;These fields express separate constraints. A reorg depth of &lt;code&gt;N&lt;/code&gt; requires at least &lt;code&gt;N + 1&lt;/code&gt; confirmations, so the effective floor must satisfy both the configured minimum and the reorg buffer. The buffer does not guarantee that a deeper reorg is impossible.&lt;/p&gt;

&lt;h2&gt;
  
  
  What &lt;code&gt;RPC_FINALIZED&lt;/code&gt; means here
&lt;/h2&gt;

&lt;p&gt;PriorSeal’s observer checks the configured RPC endpoint for the inclusion block, the current canonical block at that height, the head, and the endpoint’s finalized block.&lt;/p&gt;

&lt;p&gt;It records &lt;code&gt;FINALIZED&lt;/code&gt; only when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the inclusion hash is still canonical;&lt;/li&gt;
&lt;li&gt;the finalized height covers the inclusion block; and&lt;/li&gt;
&lt;li&gt;the configured confirmation floor is met.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the endpoint cannot provide finalized data, the execution remains &lt;code&gt;PENDING&lt;/code&gt;. If the canonical inclusion hash changes, it becomes &lt;code&gt;REORGED&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That wording matters: &lt;code&gt;RPC_FINALIZED&lt;/code&gt; records an endpoint’s observation. It is not an embedded consensus proof.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep uncertainty distinct from a policy violation
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;PENDING&lt;/code&gt; and &lt;code&gt;REORGED&lt;/code&gt; describe evidence status. Neither one, by itself, proves that an agent violated its authorization.&lt;/p&gt;

&lt;p&gt;An offline verifier can check the issuer’s signature and replay the recorded evidence and arithmetic. It does not refetch historical RPC state. A reviewer who needs independent assurance must separately assess or corroborate the RPC source and its claim.&lt;/p&gt;

&lt;p&gt;If a later reorg changes the outcome, the system should preserve that event as a separate signed receipt rather than silently rewriting the earlier record.&lt;/p&gt;

&lt;h2&gt;
  
  
  Questions to settle before signing
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;What confirmation floor does the policy require?&lt;/li&gt;
&lt;li&gt;Is an RPC-reported finalized block also required?&lt;/li&gt;
&lt;li&gt;What reorg depth is tolerated, and what happens if it is exceeded?&lt;/li&gt;
&lt;li&gt;Which endpoint supplied the finality observation?&lt;/li&gt;
&lt;li&gt;How will later changes be represented in the evidence record?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Finality criteria belong in the authorization policy before execution. A status label added afterward cannot tell a reviewer what the user actually approved.&lt;/p&gt;

&lt;p&gt;For the implementation details, see the &lt;a href="https://github.com/imokokok/PriorSeal/blob/main/docs/architecture/temporal-finality.md" rel="noopener noreferrer"&gt;temporal finality design&lt;/a&gt; and the &lt;a href="https://github.com/imokokok/PriorSeal/blob/main/sdk/README.md" rel="noopener noreferrer"&gt;PriorSeal SDK guide&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>blockchain</category>
      <category>crypto</category>
    </item>
    <item>
      <title>ERC-4337 Has Two Execution Results. Your Dashboard Should Show Both.</title>
      <dc:creator>imokokok</dc:creator>
      <pubDate>Sun, 11 Oct 2026 14:11:47 +0000</pubDate>
      <link>https://dev.to/imokokok/erc-4337-has-two-execution-results-your-dashboard-should-show-both-226h</link>
      <guid>https://dev.to/imokokok/erc-4337-has-two-execution-results-your-dashboard-should-show-both-226h</guid>
      <description>&lt;p&gt;A block explorer shows a successful transaction. A wallet dashboard marks the operation as successful too.&lt;/p&gt;

&lt;p&gt;For an ERC-4337 flow, those may be two different results.&lt;/p&gt;

&lt;p&gt;A bundler submits an outer EVM transaction to an EntryPoint contract. That transaction can contain one or more UserOperations. The outer transaction status tells you whether the EVM transaction succeeded. It does not, by itself, tell you whether every operation inside the bundle succeeded.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check the operation-level event&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When &lt;code&gt;handleOps&lt;/code&gt; completes successfully, the EntryPoint emits a &lt;code&gt;UserOperationEvent&lt;/code&gt; for each processed operation. The event includes the operation’s success flag and gas information.&lt;/p&gt;

&lt;p&gt;That means an outer transaction can succeed while one UserOperation fails. The operation can still incur gas.&lt;/p&gt;

&lt;p&gt;If the outer transaction itself reverts, the expected operation event and operation-level result are absent. The operation’s bytes appearing in the reverted transaction calldata do not establish that the UserOperation executed.&lt;/p&gt;

&lt;p&gt;A bundler-returned UserOperation hash is also not inclusion evidence. It identifies an operation for tracking. To establish inclusion, find the matching event in the transaction receipt and verify the event against the operation that was authorized.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bind the operation before submission&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;PriorSeal’s ERC-4337 adapter binds the canonical UserOperation hash into a normal authorization intent. Its observer checks the matching EntryPoint event in the outer transaction receipt. The documented adapter supports EntryPoint versions 0.6 through 0.9.&lt;/p&gt;

&lt;p&gt;Here is an integration outline:&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;bindERC4337UserOperation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;buildERC4337UserOperationIntent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;priorseal-sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;operationInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;chainId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;entryPoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;verifiedEntryPointAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;entryPointCodeHash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;verifiedEntryPointCodeHash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;entryPointVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.7&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;userOperation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;walletUserOperation&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;binding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;bindERC4337UserOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;operationInput&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;intent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;buildERC4337UserOperationIntent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;operationInput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;intentId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`withdrawal-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userOpHash&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;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;14&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;validUntil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// Authorize this intent before submitting the UserOperation.&lt;/span&gt;
&lt;span class="c1"&gt;// After the bundler includes it, observe the outer transaction hash.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The wallet supplies the UserOperation. The EntryPoint address and code hash should come from the operator’s independently reviewed deployment configuration. This snippet binds and authorizes the operation; the final observation still needs the outer transaction hash and a matching event.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Know what the binding proves&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The canonical hash ties the authorization to one UserOperation. The matching event ties that operation to an observed EntryPoint transaction.&lt;/p&gt;

&lt;p&gt;Those checks do not necessarily decode the smart account’s inner call. A Safe-specific profile can provide more detail within its documented scope; without an applicable account profile, do not claim that the receipt independently proves every inner call’s meaning or business effect.&lt;/p&gt;

&lt;p&gt;I keep three results separate in the application:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Outer transaction status&lt;/li&gt;
&lt;li&gt;UserOperation success and gas&lt;/li&gt;
&lt;li&gt;Whether the observed operation matches its authorization&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That distinction matters for both success and failure paths. An outer transaction can succeed while an operation fails. A reverted outer transaction can contain operation calldata without establishing that the operation ran.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/imokokok/PriorSeal/blob/main/docs/integrations/erc-4337.md" rel="noopener noreferrer"&gt;PriorSeal ERC-4337 guide&lt;/a&gt; documents the supported EntryPoint and account-specific profiles. The &lt;a href="https://github.com/imokokok/PriorSeal/blob/main/sdk/README.md" rel="noopener noreferrer"&gt;SDK README&lt;/a&gt; covers the broader authorization and receipt flow.&lt;/p&gt;

&lt;p&gt;Does your transaction UI show the bundler transaction and the UserOperation as separate records?&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>crypto</category>
      <category>ethereum</category>
      <category>web3</category>
    </item>
    <item>
      <title>ERC-4337 Has Two Execution Results. Your Dashboard Should Show Both.</title>
      <dc:creator>imokokok</dc:creator>
      <pubDate>Sat, 10 Oct 2026 09:32:17 +0000</pubDate>
      <link>https://dev.to/imokokok/erc-4337-has-two-execution-results-your-dashboard-should-show-both-2d38</link>
      <guid>https://dev.to/imokokok/erc-4337-has-two-execution-results-your-dashboard-should-show-both-2d38</guid>
      <description>&lt;p&gt;A block explorer shows a successful transaction. A wallet dashboard marks the operation as successful too.&lt;/p&gt;

&lt;p&gt;For an ERC-4337 flow, those may be two different results.&lt;/p&gt;

&lt;p&gt;A bundler submits an outer EVM transaction to an EntryPoint contract. That transaction can contain one or more UserOperations. The outer transaction status tells you whether the EVM transaction succeeded. It does not, by itself, tell you whether every operation inside the bundle succeeded.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check the operation-level event&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When &lt;code&gt;handleOps&lt;/code&gt; completes successfully, the EntryPoint emits a &lt;code&gt;UserOperationEvent&lt;/code&gt; for each processed operation. The event includes the operation’s success flag and gas information.&lt;/p&gt;

&lt;p&gt;That means an outer transaction can succeed while one UserOperation fails. The operation can still incur gas.&lt;/p&gt;

&lt;p&gt;If the outer transaction itself reverts, the expected operation event and operation-level result are absent. The operation’s bytes appearing in the reverted transaction calldata do not establish that the UserOperation executed.&lt;/p&gt;

&lt;p&gt;A bundler-returned UserOperation hash is also not inclusion evidence. It identifies an operation for tracking. To establish inclusion, find the matching event in the transaction receipt and verify the event against the operation that was authorized.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bind the operation before submission&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;PriorSeal’s ERC-4337 adapter binds the canonical UserOperation hash into a normal authorization intent. Its observer checks the matching EntryPoint event in the outer transaction receipt. The documented adapter supports EntryPoint versions 0.6 through 0.9.&lt;/p&gt;

&lt;p&gt;Here is an integration outline:&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;bindERC4337UserOperation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;buildERC4337UserOperationIntent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;priorseal-sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;operationInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;chainId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;entryPoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;verifiedEntryPointAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;entryPointCodeHash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;verifiedEntryPointCodeHash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;entryPointVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.7&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;userOperation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;walletUserOperation&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;binding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;bindERC4337UserOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;operationInput&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;intent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;buildERC4337UserOperationIntent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;operationInput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;intentId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`withdrawal-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userOpHash&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;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;14&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;validUntil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// Authorize this intent before submitting the UserOperation.&lt;/span&gt;
&lt;span class="c1"&gt;// After the bundler includes it, observe the outer transaction hash.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The wallet supplies the UserOperation. The EntryPoint address and code hash should come from the operator’s independently reviewed deployment configuration. This snippet binds and authorizes the operation; the final observation still needs the outer transaction hash and a matching event.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Know what the binding proves&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The canonical hash ties the authorization to one UserOperation. The matching event ties that operation to an observed EntryPoint transaction.&lt;/p&gt;

&lt;p&gt;Those checks do not necessarily decode the smart account’s inner call. A Safe-specific profile can provide more detail within its documented scope; without an applicable account profile, do not claim that the receipt independently proves every inner call’s meaning or business effect.&lt;/p&gt;

&lt;p&gt;I keep three results separate in the application:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Outer transaction status&lt;/li&gt;
&lt;li&gt;UserOperation success and gas&lt;/li&gt;
&lt;li&gt;Whether the observed operation matches its authorization&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That distinction matters for both success and failure paths. An outer transaction can succeed while an operation fails. A reverted outer transaction can contain operation calldata without establishing that the operation ran.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/imokokok/PriorSeal/blob/main/docs/integrations/erc-4337.md" rel="noopener noreferrer"&gt;PriorSeal ERC-4337 guide&lt;/a&gt; documents the supported EntryPoint and account-specific profiles. The &lt;a href="https://github.com/imokokok/PriorSeal/blob/main/sdk/README.md" rel="noopener noreferrer"&gt;SDK README&lt;/a&gt; covers the broader authorization and receipt flow.&lt;/p&gt;

&lt;p&gt;Does your transaction UI show the bundler transaction and the UserOperation as separate records?&lt;/p&gt;

</description>
      <category>web3</category>
      <category>ai</category>
    </item>
    <item>
      <title>A Valid Signature Is Not Yet a Trusted Receipt</title>
      <dc:creator>imokokok</dc:creator>
      <pubDate>Fri, 09 Oct 2026 16:13:53 +0000</pubDate>
      <link>https://dev.to/imokokok/a-valid-signature-is-not-yet-a-trusted-receipt-13no</link>
      <guid>https://dev.to/imokokok/a-valid-signature-is-not-yet-a-trusted-receipt-13no</guid>
      <description>&lt;p&gt;A local verifier returns &lt;code&gt;valid: true&lt;/code&gt; for an execution receipt.&lt;/p&gt;

&lt;p&gt;That answers a cryptographic question: does the receipt’s signature match the public key supplied to the verifier, and do the signed fields pass the supported checks?&lt;/p&gt;

&lt;p&gt;It does not answer a separate identity question: &lt;strong&gt;why should the reviewer trust that this key belongs to the expected issuer?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A signature proves control of a private key. The reviewer still needs an independently established link between that key and the issuer they intended to trust.&lt;/p&gt;

&lt;p&gt;This is why a key registry included in the same downloaded bundle should be treated as discovery data. If a verifier accepts a receipt’s bundled key as its own trust source, a party could create a new key, sign a fabricated receipt, and satisfy that verifier’s signature check.&lt;/p&gt;

&lt;p&gt;The trust configuration should come from a separate, reviewed source. It should identify the expected issuer and key, the deployment audience, and the key’s validity or revocation status.&lt;/p&gt;

&lt;p&gt;Here is the shape of a local verification call with &lt;code&gt;priorseal-sdk&lt;/code&gt;:&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;verifyReceiptLocally&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;priorseal-sdk/verifier&lt;/span&gt;&lt;span class="dl"&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;verifyReceiptLocally&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;receipt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;trustedKeys&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;independentlyConfirmedKeyRegistry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;expectedAudience&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;your-deployment-audience&lt;/span&gt;&lt;span class="dl"&gt;'&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="p"&gt;(&lt;/span&gt;&lt;span class="o"&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;valid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Receipt verification failed: &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;code&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;verificationScope&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;verificationScope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;outcome&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;outcome&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;executionStatus&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;executionStatus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;complianceStatus&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;complianceStatus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;requiredExternalChecks&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;requiredExternalChecks&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 application supplies the receipt, the independently confirmed key registry, and the expected audience. The verifier performs no network requests. It checks signatures and receipt relationships within its supported scope.&lt;/p&gt;

&lt;p&gt;The result keeps several claims distinct:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;valid&lt;/code&gt; reports whether verification passed with the supplied trust configuration.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;outcome&lt;/code&gt; reports the execution result recorded in the receipt.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;complianceStatus&lt;/code&gt; reports whether the correlated execution matched the authorization, when assessable.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;requiredExternalChecks&lt;/code&gt; lists checks the offline verifier cannot complete, such as ERC-1271 state or EVM anchor inclusion.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A local result that requires external checks should remain visibly incomplete until those checks are handled. Offline verification does not mean every chain-dependent claim has been independently re-established.&lt;/p&gt;

&lt;p&gt;The same principle applies when connecting Insight and PriorSeal. Insight’s oracle assessment and PriorSeal’s authorization and execution receipt keep separate trust roots. A commitment can show that a digest was included in an authorization; it does not make PriorSeal the issuer of Insight’s assessment.&lt;/p&gt;

&lt;p&gt;Before displaying one green “Verified” badge, ask what your verifier actually established:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Did the signature match?&lt;/li&gt;
&lt;li&gt;Was the signing key trusted independently?&lt;/li&gt;
&lt;li&gt;Did the receipt target the expected audience?&lt;/li&gt;
&lt;li&gt;Did the verifier finish all required checks?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A signature is a strong piece of evidence. Its meaning depends on the trust configuration around it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/imokokok/PriorSeal/blob/main/sdk/README.md#independent-local-verification" rel="noopener noreferrer"&gt;PriorSeal independent local verification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/imokokok/PriorSeal#what-the-evidence-covers" rel="noopener noreferrer"&gt;PriorSeal evidence scope&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/imokokok/Insight/blob/main/sdk/README.md" rel="noopener noreferrer"&gt;Insight SDK and product boundaries&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>web3</category>
    </item>
    <item>
      <title>Insight: a pre-trade safety oracle API for AI agents — paid per call via x402 on Base</title>
      <dc:creator>imokokok</dc:creator>
      <pubDate>Wed, 07 Oct 2026 13:30:23 +0000</pubDate>
      <link>https://dev.to/imokokok/insight-a-pre-trade-safety-oracle-api-for-ai-agents-paid-per-call-via-x402-on-base-1gmg</link>
      <guid>https://dev.to/imokokok/insight-a-pre-trade-safety-oracle-api-for-ai-agents-paid-per-call-via-x402-on-base-1gmg</guid>
      <description>&lt;p&gt;TL;DR: &lt;a href="https://www.oracleinsight.xyz" rel="noopener noreferrer"&gt;Insight&lt;/a&gt; gives AI agents a pre-trade safety check for DeFi — oracle-manipulation-aware PASS/WARN/BLOCK verdicts, each check optionally backed by an EIP-712 signed attestation that anyone can verify from the signature bytes alone. Paid per call with USDC via &lt;a href="https://www.x402.org" rel="noopener noreferrer"&gt;x402&lt;/a&gt; on Base mainnet. No signup, no API key for the paid path — the payment IS the auth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why
&lt;/h2&gt;

&lt;p&gt;If you're building an agent that swaps or borrows on-chain, price-feed integrity is the attack surface you don't control. Flash-loan oracle manipulation is still one of the most common exploit patterns. Insight checks the trade before execution: consensus price across providers, cross-provider agreement, stale-data risk, manipulation risk score, and a recommended max position — returned as a single verdict.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integration
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;REST (x402, $0.02/call in USDC):&lt;/strong&gt;​&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"https://www.oracleinsight.xyz/api/v1/safety/pre-trade?asset=ETH&amp;amp;chainId=1&amp;amp;action=swap&amp;amp;tradeAmountUsd=1000"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The 402 response carries a standard x402 v2 challenge; any x402 client library (e.g. the official &lt;code&gt;x402-fetch&lt;/code&gt; wrapper) signs and retries automatically. Gasless for the caller (EIP-3009 &lt;code&gt;transferWithAuthorization&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keyless verification (free):&lt;/strong&gt;​&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://www.oracleinsight.xyz/api/v1/safety/attestation/verify &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{ ...attestation... }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;MCP (40 tools, streamable HTTP):&lt;/strong&gt;​&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://www.oracleinsight.xyz/api/mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Anonymous &lt;code&gt;initialize&lt;/code&gt; / &lt;code&gt;tools/list&lt;/code&gt; — browse the whole catalog with no credentials. Single &lt;code&gt;tools/call&lt;/code&gt; is metered on-chain via x402, priced by tool class ($0.002–$0.04); failed calls are never charged (settlement only happens after a successful tool result).&lt;/p&gt;

&lt;h2&gt;
  
  
  Discovery
&lt;/h2&gt;

&lt;p&gt;Everything is self-describing, so agents can find and use it without a human:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/.well-known/x402&lt;/code&gt; — x402 resource manifest&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/.well-known/mcp/server-card.json&lt;/code&gt; — SEP-1649 static server card (40 tools)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/llms.txt&lt;/code&gt;, &lt;code&gt;/openapi.json&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also listed on the official MCP Registry (&lt;code&gt;io.github.imokokok/insight-oracle&lt;/code&gt;), Smithery (&lt;code&gt;@imokokok123/insight-oracle&lt;/code&gt;), agent402.tools, and the CDP Bazaar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Feedback welcome
&lt;/h2&gt;

&lt;p&gt;Particularly interested in: agent-framework integrations (LangChain / Eliza / GAME), additional chains, and what other pre-trade signals you'd want checked. Repo is at &lt;a href="https://github.com/imokokok/Insight" rel="noopener noreferrer"&gt;github.com/imokokok/Insight&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>web3</category>
    </item>
    <item>
      <title>Why a Successful Agent Transaction Can Still Fail Authorization Checks</title>
      <dc:creator>imokokok</dc:creator>
      <pubDate>Sat, 03 Oct 2026 16:17:23 +0000</pubDate>
      <link>https://dev.to/imokokok/why-a-successful-agent-transaction-can-still-fail-authorization-checks-2pm1</link>
      <guid>https://dev.to/imokokok/why-a-successful-agent-transaction-can-still-fail-authorization-checks-2pm1</guid>
      <description>&lt;p&gt;An AI agent submits a transaction. It executes without reverting, and the dashboard displays “Success.”&lt;/p&gt;

&lt;p&gt;That label leaves an important question unanswered: did the agent execute the call the user authorized?&lt;/p&gt;

&lt;p&gt;Consider a hypothetical swap. The user approves calldata that sends the output to wallet A. The observed transaction uses the same chain, executor, and nonce, but different calldata directing the output to wallet B.&lt;/p&gt;

&lt;p&gt;The execution can complete while the authorization comparison fails.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A transaction review needs three separate results:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Evidence validity:&lt;/strong&gt; do the receipt, signatures, hashes, and supported relationships pass verification under the reviewer’s trusted configuration?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execution outcome:&lt;/strong&gt; what execution state does the evidence report?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authorization compliance:&lt;/strong&gt; does the correlated execution match the signed authorization within the supported checks?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In PriorSeal receipt v3, a verifier summary can therefore look 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;"valid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"OK"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"outcome"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"COMPLETED"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"executionStatus"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CONFIRMED"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"complianceStatus"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NON_COMPLIANT"&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;This is an illustrative result, not a record of a live transaction.&lt;/p&gt;

&lt;p&gt;The issuer signed a record of the mismatch. The verifier can accept that record while confirming that the observed call differed from the authorization. In the calldata example, the receipt’s compliance reasons include &lt;code&gt;CALLDATA_MISMATCH&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Editing the receipt after signing would be a different problem: its integrity verification would fail.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep those results separate in the application.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here is a small integration outline using the local verifier:&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;verifyReceiptLocally&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;priorseal-sdk/verifier&lt;/span&gt;&lt;span class="dl"&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;verifyReceiptLocally&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;receipt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;trustedKeys&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;confirmedKeys&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;expectedAudience&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;confirmedAudience&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="p"&gt;(&lt;/span&gt;&lt;span class="o"&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;valid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&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;code&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="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;requiredExternalChecks&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="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Complete the required external checks first&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;evidence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;VERIFIED_WITHIN_LOCAL_SCOPE&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;execution&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;outcome&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;authorization&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;complianceStatus&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;NOT_ASSESSABLE&lt;/span&gt;&lt;span class="dl"&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 application supplies the exported &lt;code&gt;receipt&lt;/code&gt;, independently confirmed issuer keys, and the expected deployment audience. A key included in an imported bundle does not establish its own trustworthiness.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/imokokok/PriorSeal/blob/main/sdk/README.md" rel="noopener noreferrer"&gt;SDK verifier documentation&lt;/a&gt; describes the supported checks. ERC-1271 authorization and EVM anchor evidence can require additional chain-state verification. The local verifier reports those requirements explicitly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;“Not assessable” also needs its own place in the interface.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Missing evidence, insufficient finality, a reorg, or an unrelated transaction may prevent the verifier from assessing authorization compliance. Those cases should remain &lt;code&gt;NOT_ASSESSABLE&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A confirmed transaction with the expected chain, executor, and nonce but changed calldata provides a different result: an attributable mismatch.&lt;/p&gt;

&lt;p&gt;These distinctions also explain why authorization review and market risk assessment remain separate. An authorized trade can still produce a poor economic result. Insight supplies oracle and risk assessments; PriorSeal supplies authorization and execution evidence. Their &lt;a href="https://github.com/imokokok/Insight/blob/main/sdk/README.md" rel="noopener noreferrer"&gt;combined workflow&lt;/a&gt; preserves both scopes.&lt;/p&gt;

&lt;p&gt;A receipt records the evidence available for review. Preventing an unauthorized transaction also requires the signing and submission paths to enforce the authorization checks.&lt;/p&gt;

&lt;p&gt;If your application currently displays one “Success” badge, what would a user see when execution completes but the authorization comparison fails?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
    </item>
    <item>
      <title>When an AI Agent’s Swap Times Out, What Can It Safely Retry?</title>
      <dc:creator>imokokok</dc:creator>
      <pubDate>Fri, 02 Oct 2026 10:56:11 +0000</pubDate>
      <link>https://dev.to/imokokok/when-an-ai-agents-swap-times-out-what-can-it-safely-retry-54b8</link>
      <guid>https://dev.to/imokokok/when-an-ai-agents-swap-times-out-what-can-it-safely-retry-54b8</guid>
      <description>&lt;p&gt;An AI agent submits a WETH → USDC swap. The RPC request times out immediately afterward.&lt;/p&gt;

&lt;p&gt;The application did not receive a transaction hash. That does &lt;strong&gt;not&lt;/strong&gt; establish that the transaction was never broadcast. A retry routine that simply builds and signs another swap may create a second action while the first is still pending.&lt;/p&gt;

&lt;p&gt;The useful question is: &lt;strong&gt;which operation are we retrying?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Observe the original attempt
&lt;/h2&gt;

&lt;p&gt;Persist the prepared call and its identifiers before dispatch. Record the chain, sender, nonce, target, calldata hash, authorization ID, and transaction hash whenever one becomes available.&lt;/p&gt;

&lt;p&gt;After a timeout, query the known hash and sender nonce through your configured chain observers. Keep these outcomes separate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pending:&lt;/strong&gt; continue observing; do not infer failure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not found or RPC unavailable:&lt;/strong&gt; the result is still uncertain. One missing response is not proof that nothing was broadcast.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Confirmed:&lt;/strong&gt; recover the evidence for that execution. Do not submit another swap to fix a missing receipt.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reverted:&lt;/strong&gt; the transaction reached the chain but failed. A new swap is a new decision.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reorged:&lt;/strong&gt; preserve the earlier observation and reassess the canonical chain and required finality.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;PriorSeal’s &lt;a href="https://github.com/imokokok/PriorSeal/blob/main/docs/architecture/lifecycle.md" rel="noopener noreferrer"&gt;lifecycle documentation&lt;/a&gt; keeps pending, unavailable, reverted, and reorged states explicit. A confirmed or reverted transaction correlated with a single-use authorization consumes that authorization; an action mismatch does not reopen it.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Retry evidence collection without executing again
&lt;/h2&gt;

&lt;p&gt;If the transaction hash is known and the combined Insight–PriorSeal workflow has saved a checkpoint, the application can resume evidence recovery:&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;InsightGuard&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;oracle-insight-guard&lt;/span&gt;&lt;span class="dl"&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;guard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;InsightGuard&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;INSIGHT_API_KEY&lt;/span&gt;&lt;span class="o"&gt;!&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;checkpoint&lt;/span&gt; &lt;span class="o"&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;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;loadCheckpoint&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;recovered&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;guard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resumeAssessedSwapExecution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;checkpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;priorSealClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;saveCheckpoint&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;recovered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checkpoint&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application supplies &lt;code&gt;loadCheckpoint&lt;/code&gt;, &lt;code&gt;saveCheckpoint&lt;/code&gt;, and &lt;code&gt;priorSealClient&lt;/code&gt;. This recovery path has no transaction signing or submission callback. It retains existing evidence, checks the existing observation job, and requests missing artifacts. Insight’s &lt;a href="https://github.com/imokokok/Insight/blob/main/sdk/README.md" rel="noopener noreferrer"&gt;SDK guide&lt;/a&gt; also provides an evidence-only receipt retry for its independent execution flow.&lt;/p&gt;

&lt;p&gt;This code does &lt;strong&gt;not&lt;/strong&gt; resolve a lost broadcast response when no transaction hash or checkpoint was recorded. That attempt remains uncertain until it is reconciled against chain and signer state.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Treat a new execution as a new decision
&lt;/h2&gt;

&lt;p&gt;Only consider another trade after assessing whether the original could still execute. Rebuild and review the exact call, refresh the oracle and route evidence, and obtain a new time-bounded authorization when the previous single-use authorization has been consumed or the call has changed.&lt;/p&gt;

&lt;p&gt;Insight’s &lt;a href="https://github.com/imokokok/Insight/blob/main/docs/swap-transaction-risk.md" rel="noopener noreferrer"&gt;transaction-specific review&lt;/a&gt; describes a simulated quote at one observed block. Changed calldata or expired evidence requires a fresh review. A past favorable assessment cannot approve a later transaction by itself.&lt;/p&gt;

&lt;p&gt;The central recovery rule is simple: &lt;strong&gt;retry observation and missing evidence; never turn an uncertain response into automatic permission for another trade.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What does your agent persist before it asks a signer to broadcast?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>web3</category>
    </item>
    <item>
      <title>One AI Swap, Three Prices: What Each Number Can Actually Prove</title>
      <dc:creator>imokokok</dc:creator>
      <pubDate>Thu, 01 Oct 2026 10:29:47 +0000</pubDate>
      <link>https://dev.to/imokokok/one-ai-swap-three-prices-what-each-number-can-actually-prove-42gd</link>
      <guid>https://dev.to/imokokok/one-ai-swap-three-prices-what-each-number-can-actually-prove-42gd</guid>
      <description>&lt;p&gt;An AI agent proposes a WETH → USDC swap. Before execution, it may see an oracle reference price and a simulated route quote. After execution, it can observe the actual fill.&lt;/p&gt;

&lt;p&gt;Those are three different numbers backed by three different kinds of evidence. Treating them as interchangeable can hide a bad route, an overbroad authorization, or an unexpected execution result.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Oracle reference: the comparison point
&lt;/h2&gt;

&lt;p&gt;An independent oracle assessment answers a question about market data: what reference price and risk signals were available for WETH and USDC at that time?&lt;/p&gt;

&lt;p&gt;It gives the agent a basis for reviewing a proposed trade. It does not say that a particular router will deliver that price.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Simulated quote: this call at this block
&lt;/h2&gt;

&lt;p&gt;A route quote needs to be tied to the transaction the agent actually intends to submit: chain, sender, router, calldata, token amounts, recipient, minimum output, and deadline.&lt;/p&gt;

&lt;p&gt;Insight's &lt;code&gt;assessV3Swap()&lt;/code&gt; reviews a prepared Uniswap V3 &lt;code&gt;exactInputSingle&lt;/code&gt; call against two signed pre-trade oracle assessments. It checks the router's reviewed runtime code hash, decodes the call, and simulates it from the intended sender at one RPC block. It then compares the simulated output with the oracle reference and the transaction's minimum output.&lt;/p&gt;

&lt;p&gt;A simplified integration looks like this:&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;InsightGuard&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;oracle-insight-guard&lt;/span&gt;&lt;span class="dl"&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;guard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;InsightGuard&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;INSIGHT_API_KEY&lt;/span&gt;&lt;span class="o"&gt;!&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;transactionRisk&lt;/span&gt; &lt;span class="p"&gt;}&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;guard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assessV3Swap&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WETH&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;destinationAsset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;USDC&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;chainId&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="na"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;swap&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;tradeAmountUsd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;USDC&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;destinationAsset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WETH&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;chainId&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="na"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;swap&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;tradeAmountUsd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;receipt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;settlementChainId&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="na"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;preparedExactCall&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;routerCodeHash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;reviewedRouterCodeHash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;publicClient&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="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transactionRisk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ACCEPTABLE&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&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;transactionRisk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&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;transactionRisk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reasonCodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;, &lt;/span&gt;&lt;span class="dl"&gt;'&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;preparedExactCall&lt;/code&gt; and &lt;code&gt;publicClient&lt;/code&gt; come from the integration. The expected router code hash must come from an independently reviewed deployment configuration, not from the agent proposing the trade. The USD amount is illustrative; a real integration must use the intended trade scope.&lt;/p&gt;

&lt;p&gt;The result has three possible statuses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ACCEPTABLE&lt;/code&gt;: the exact call met the configured policy at the observed block.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;RISK_REJECTED&lt;/code&gt;: available evidence showed a policy or minimum-output failure.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;UNASSESSABLE&lt;/code&gt;: required evidence was missing or could not be checked. This is never approval.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The transaction review is local, unsigned SDK output. The signed Insight proofs cover the oracle assessment; they do not turn an RPC simulation into a guaranteed future fill.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Actual fill: what happened after submission
&lt;/h2&gt;

&lt;p&gt;The simulated quote describes one block. Between review and inclusion, pool state can change. A post-trade check therefore needs the observed transaction, receipt, relevant token movements, and the finality level appropriate to the application.&lt;/p&gt;

&lt;p&gt;Compare the actual input and output with the authorized call and the earlier evidence. Preserve the original review even if the transaction fails, is reorganized, or remains uncertain. A transaction hash by itself is not a complete account of the fill.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where authorization fits
&lt;/h2&gt;

&lt;p&gt;Price review and permission review answer different questions. If PriorSeal is used alongside Insight, it can bind user or organizational authorization to the exact call and produce evidence relating authorization to observed EVM execution. It does not make the oracle price correct or guarantee the output amount.&lt;/p&gt;

&lt;p&gt;The operational rule is simple: review the prepared call immediately before authorization, authorize that exact call, and examine the observed result afterward. If calldata changes or evidence expires, review again.&lt;/p&gt;

&lt;p&gt;The current &lt;code&gt;assessV3Swap()&lt;/code&gt; adapter covers the original Uniswap V3 SwapRouter &lt;code&gt;exactInputSingle&lt;/code&gt; path described in the documentation. Other routers need separately reviewed adapters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Technical references:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/imokokok/Insight/blob/main/docs/swap-transaction-risk.md" rel="noopener noreferrer"&gt;Transaction-specific swap risk review&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/imokokok/Insight/blob/main/sdk/README.md" rel="noopener noreferrer"&gt;Insight SDK README&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/imokokok/PriorSeal" rel="noopener noreferrer"&gt;PriorSeal repository&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>typescript</category>
      <category>cryptocurrency</category>
    </item>
    <item>
      <title>A Healthy Oracle Sample Shouldn’t Automatically Resume an AI Agent</title>
      <dc:creator>imokokok</dc:creator>
      <pubDate>Wed, 30 Sep 2026 08:54:49 +0000</pubDate>
      <link>https://dev.to/imokokok/a-healthy-oracle-sample-shouldnt-automatically-resume-an-ai-agent-5afc</link>
      <guid>https://dev.to/imokokok/a-healthy-oracle-sample-shouldnt-automatically-resume-an-ai-agent-5afc</guid>
      <description>&lt;p&gt;A long-running AI agent checks oracle conditions and receives a &lt;code&gt;halt&lt;/code&gt; recommendation. Its strategy pauses.&lt;/p&gt;

&lt;p&gt;The next sample looks healthy. Should the agent immediately resume?&lt;/p&gt;

&lt;p&gt;I would treat recovery as a separate decision. A single healthy response does not establish that an incident has ended, and a process restart should not erase the pause.&lt;/p&gt;

&lt;p&gt;Here is how I approach that boundary with Insight Oracle Watch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the halt across restarts
&lt;/h2&gt;

&lt;p&gt;Oracle Watch can retain states such as &lt;code&gt;halted&lt;/code&gt;, &lt;code&gt;recovering&lt;/code&gt;, and &lt;code&gt;monitor_unavailable&lt;/code&gt; through a &lt;code&gt;stateAdapter&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The adapter must use storage appropriate for your deployment. An in-memory map will lose its state on restart; multiple workers need a shared, coordinated store.&lt;/p&gt;

&lt;p&gt;This example accepts the store and application actions as dependencies:&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;InsightGuard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;OracleWatchTarget&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;WatchStateAdapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;oracle-insight-guard&lt;/span&gt;&lt;span class="dl"&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;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;OracleWatchTarget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ETH&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ethereum&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;startGuardedWatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;guard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;InsightGuard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;stateAdapter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;WatchStateAdapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;pauseNewActions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;notifyOperator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;guard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;stopOnHalt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;recoveryHealthySamples&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="nx"&gt;stateAdapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="na"&gt;onHalt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;pauseNewActions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Oracle Watch: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reason&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="na"&gt;onIncident&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;pauseNewActions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Watch incident: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;incidentKind&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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;notifyOperator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Watch incident: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;incidentId&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="na"&gt;onRecoveryReady&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;notifyOperator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Fresh samples are ready for review&lt;/span&gt;&lt;span class="dl"&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;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;assertCanStartNewAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;guard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;InsightGuard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&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;guard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isHalted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Oracle Watch requires operator review&lt;/span&gt;&lt;span class="dl"&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;Connect &lt;code&gt;pauseNewActions&lt;/code&gt; to your strategy controller. Call &lt;code&gt;assertCanStartNewAction()&lt;/code&gt; at the application’s execution boundary. If you use the Guard’s swap execution flow, pass the same &lt;code&gt;watchTarget&lt;/code&gt; so its Watch halt is applied there too.&lt;/p&gt;

&lt;p&gt;Callbacks provide notifications and application behavior. The execution boundary must still check the halt state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recovery has two steps
&lt;/h2&gt;

&lt;p&gt;With &lt;code&gt;stopOnHalt: false&lt;/code&gt;, Watch continues collecting signals after a halt.&lt;/p&gt;

&lt;p&gt;In this example, two consecutive fresh healthy samples make recovery &lt;strong&gt;ready for review&lt;/strong&gt;. They do not clear the execution halt.&lt;/p&gt;

&lt;p&gt;After the operator reviews the incident and current conditions, the application can call:&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;await&lt;/span&gt; &lt;span class="nx"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;acknowledgeRecovery&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here &lt;code&gt;watch&lt;/code&gt; is the handle returned by &lt;code&gt;startGuardedWatch()&lt;/code&gt;. Acknowledgement clears the Watch halt when its recovery conditions are satisfied. It does not call a wallet, submit a trade, or resume your strategy on its own.&lt;/p&gt;

&lt;p&gt;The application must make its own subsequent execution decision, including any current pre-trade assessment and authorization requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Treat monitoring availability as a state
&lt;/h2&gt;

&lt;p&gt;A failed Watch request, exhausted API budget, or storage failure also matters to a running strategy.&lt;/p&gt;

&lt;p&gt;Preserve the incident reason and make monitoring availability visible. The SDK retains a local halt when durable state cannot be saved. Your execution path should check its gate instead of assuming that missing monitoring means healthy conditions.&lt;/p&gt;

&lt;p&gt;Oracle Watch’s default cadence is 15 minutes, matching Insight’s published snapshot cadence. It provides scheduled monitoring, not second-by-second market observation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The design question
&lt;/h2&gt;

&lt;p&gt;A useful state machine separates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Halted:&lt;/strong&gt; a signal or monitoring incident stopped new actions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recovering:&lt;/strong&gt; fresh healthy samples have arrived; the halt remains active.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Acknowledged:&lt;/strong&gt; recovery conditions were reviewed and the Watch halt was explicitly cleared.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For an automated strategy, what evidence should be required before a halted agent can take its next action?&lt;/p&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/imokokok/Insight/blob/main/sdk/README.md#watch-a-running-strategy" rel="noopener noreferrer"&gt;Insight SDK: watching a running strategy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/imokokok/Insight/blob/main/sdk/README.md#durable-watch-incidents-and-budget-planning" rel="noopener noreferrer"&gt;Durable Watch incidents&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.oracleinsight.xyz/" rel="noopener noreferrer"&gt;Insight&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>web3</category>
    </item>
    <item>
      <title>A Public Key Inside a Receipt Bundle Is Not a Trust Root</title>
      <dc:creator>imokokok</dc:creator>
      <pubDate>Tue, 29 Sep 2026 10:10:41 +0000</pubDate>
      <link>https://dev.to/imokokok/a-public-key-inside-a-receipt-bundle-is-not-a-trust-root-3e4o</link>
      <guid>https://dev.to/imokokok/a-public-key-inside-a-receipt-bundle-is-not-a-trust-root-3e4o</guid>
      <description>&lt;p&gt;A portable transaction-evidence bundle may contain both a signed receipt and a public key.&lt;/p&gt;

&lt;p&gt;That makes the bundle convenient to inspect. It also creates a question for the reviewer: &lt;strong&gt;how was that key confirmed as the expected issuer’s key?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This post shows how to keep bundle validation and issuer trust separate when verifying a PriorSeal receipt locally.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with a synthetic receipt
&lt;/h2&gt;

&lt;p&gt;PriorSeal’s repository includes an offline example. With Node.js 22 or later:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/imokokok/PriorSeal.git
&lt;span class="nb"&gt;cd &lt;/span&gt;PriorSeal
npm ci
npm run example:receipt
npm run verify:receipt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The example creates a temporary key and synthetic execution evidence. It needs no wallet, RPC endpoint, or funds.&lt;/p&gt;

&lt;p&gt;The expected verification output includes &lt;code&gt;valid: true&lt;/code&gt;, &lt;code&gt;code: OK&lt;/code&gt;, and separate execution and compliance statuses.&lt;/p&gt;

&lt;p&gt;Because the example generates its own temporary key, it demonstrates the mechanics of verification. Reviewing a receipt from another issuer adds a separate task: establish which issuer key you trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bundle and the trust profile have different jobs
&lt;/h2&gt;

&lt;p&gt;A portable bundle supplies the evidence to examine. Its embedded key registry is useful discovery information.&lt;/p&gt;

&lt;p&gt;The reviewer’s trust profile supplies independently confirmed keys and the expected audience. Its provenance must be checked outside the bundle. Merely placing copied bundle data in a second file does not establish independent trust.&lt;/p&gt;

&lt;p&gt;PriorSeal’s trust-profile parser checks the profile’s structure. Parsing alone cannot confirm its source.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify using independently confirmed trust
&lt;/h2&gt;

&lt;p&gt;Install the SDK and a TypeScript runner:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;priorseal-sdk@0.8.0
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; tsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save this as &lt;code&gt;verify-bundle.mts&lt;/code&gt;:&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;readFile&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node:fs/promises&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;parseTrustProfile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;verifyVerificationBundleLocally&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;priorseal-sdk/verifier&lt;/span&gt;&lt;span class="dl"&gt;'&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;bundlePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;trustPath&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;argv&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;2&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;bundlePath&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;trustPath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Usage: verify-bundle.mts bundle.json confirmed-trust-profile.json&lt;/span&gt;&lt;span class="dl"&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bundle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt; &lt;span class="o"&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;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bundlePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;'&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;trustValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt; &lt;span class="o"&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;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;trustPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;'&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;trust&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseTrustProfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;trustValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Confirm the profile's source and expected issuer independently.&lt;/span&gt;
&lt;span class="c1"&gt;// Its source and confirmedAt fields do not prove provenance by themselves.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;verifyVerificationBundleLocally&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bundle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;trustedKeys&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;priorseal.keys.v1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;issuer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;trust&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;issuer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;trust&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;expectedAudience&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;trust&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;audience&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&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="na"&gt;valid&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;valid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;code&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;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;verificationScope&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;verificationScope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;requiredExternalChecks&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;requiredExternalChecks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="kc"&gt;null&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="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;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;valid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exitCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;else&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;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;requiredExternalChecks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exitCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it with an exported bundle and a trust profile whose issuer, audience, and keys you have confirmed independently:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx tsx verify-bundle.mts bundle.json confirmed-trust-profile.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The verifier checks the bundle structure and hash, then checks the receipt using the keys supplied by the reviewer. It does not promote &lt;code&gt;bundle.keyRegistry&lt;/code&gt; into trusted configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read the result within its scope
&lt;/h2&gt;

&lt;p&gt;Inspect &lt;code&gt;valid&lt;/code&gt;, &lt;code&gt;code&lt;/code&gt;, and &lt;code&gt;verificationScope&lt;/code&gt; together.&lt;/p&gt;

&lt;p&gt;If &lt;code&gt;requiredExternalChecks&lt;/code&gt; contains entries, further chain-state checks remain. ERC-1271 contract-wallet authority and EVM anchors are examples that can require external verification.&lt;/p&gt;

&lt;p&gt;A locally valid receipt supports the signed claims and relationships checked within that verification scope. Review the execution state and authorization-compliance result separately. The receipt does not establish that a trade was profitable or that every external data source was economically correct.&lt;/p&gt;

&lt;h2&gt;
  
  
  Review checklist
&lt;/h2&gt;

&lt;p&gt;Before accepting a third-party evidence bundle, ask:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Where did the trusted issuer key and expected audience come from?&lt;/li&gt;
&lt;li&gt;Did the bundle and receipt pass local verification?&lt;/li&gt;
&lt;li&gt;What authorization and execution relationship was actually checked?&lt;/li&gt;
&lt;li&gt;Are external chain-state checks still required?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;How does your team distribute and confirm trusted issuer keys for offline review?&lt;/p&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/imokokok/PriorSeal/blob/main/sdk/README.md" rel="noopener noreferrer"&gt;PriorSeal SDK verification guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/imokokok/PriorSeal/blob/main/docs/architecture/evidence-relationship-levels.md" rel="noopener noreferrer"&gt;Evidence relationships and limits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://priorseal.xyz/" rel="noopener noreferrer"&gt;PriorSeal&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>web3</category>
    </item>
    <item>
      <title>An AI trading agent paused. Can you tell why?</title>
      <dc:creator>imokokok</dc:creator>
      <pubDate>Mon, 28 Sep 2026 08:42:36 +0000</pubDate>
      <link>https://dev.to/imokokok/an-ai-trading-agent-paused-can-you-tell-why-1anf</link>
      <guid>https://dev.to/imokokok/an-ai-trading-agent-paused-can-you-tell-why-1anf</guid>
      <description>&lt;p&gt;Imagine an agent preparing an ETH to USDC swap. It cannot complete its price check, so it pauses.&lt;/p&gt;

&lt;p&gt;Six months later, an auditor finds an empty &lt;code&gt;price&lt;/code&gt; field. What happened?&lt;/p&gt;

&lt;p&gt;Perhaps the agent retrieved quotes, but too few met its freshness or independence requirements. Perhaps a provider timed out and the quotes were never retrieved. Those are different events, yet a nullable field makes them look the same.&lt;/p&gt;

&lt;p&gt;I would model the outcomes explicitly:&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;type&lt;/span&gt; &lt;span class="nx"&gt;PriceCheckResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;passed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nl"&gt;policyId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nl"&gt;evidenceDigest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;insufficient_evidence&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nl"&gt;policyId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nl"&gt;reasonCodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;retrieval_failed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nl"&gt;policyId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nl"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nl"&gt;errorCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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 &lt;code&gt;policyId&lt;/code&gt; matters because “insufficient” is a judgment against a particular set of requirements. The same observations might pass one policy and fail another. A reviewer needs the policy that applied at decision time, not just the agent’s final verdict.&lt;/p&gt;

&lt;p&gt;I would keep this assessment separate from two later records: what exact action the user authorized, and what execution was observed. A valid price check does not authorize a transaction. A transaction hash alone does not explain the decision or the authorization that preceded it.&lt;/p&gt;

&lt;p&gt;This separation guides my work on &lt;a href="https://github.com/imokokok/Insight" rel="noopener noreferrer"&gt;Insight&lt;/a&gt; for oracle evidence and &lt;a href="https://github.com/imokokok/PriorSeal" rel="noopener noreferrer"&gt;PriorSeal&lt;/a&gt; for EVM authorization and execution evidence.&lt;/p&gt;

&lt;p&gt;How do you preserve policy context in an audit trail: a full snapshot, an immutable reference, or both?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>web3</category>
    </item>
    <item>
      <title>Recovering an AI Agent’s Transaction Observation After a Timeout</title>
      <dc:creator>imokokok</dc:creator>
      <pubDate>Sun, 27 Sep 2026 10:50:31 +0000</pubDate>
      <link>https://dev.to/imokokok/recovering-an-ai-agents-transaction-observation-after-a-timeout-1897</link>
      <guid>https://dev.to/imokokok/recovering-an-ai-agents-transaction-observation-after-a-timeout-1897</guid>
      <description>&lt;p&gt;An agent submits a transaction, receives a transaction hash, and starts waiting for execution evidence.&lt;/p&gt;

&lt;p&gt;Then the client’s wait expires.&lt;/p&gt;

&lt;p&gt;What should the application preserve, and how can it continue observing the original transaction after a restart?&lt;/p&gt;

&lt;p&gt;Here is a small recovery example using PriorSeal’s TypeScript SDK.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Persist the operation identifiers
&lt;/h2&gt;

&lt;p&gt;Save the original transaction hash, chain ID, and authorization ID when they become available.&lt;/p&gt;

&lt;p&gt;When &lt;code&gt;observeExecution()&lt;/code&gt; returns an &lt;code&gt;observationJob&lt;/code&gt;, persist its &lt;code&gt;jobId&lt;/code&gt; before continuing to wait.&lt;/p&gt;

&lt;p&gt;These identifiers let a restarted process locate the original operation. Store them in durable storage appropriate for your deployment.&lt;/p&gt;

&lt;p&gt;If the initial observation response was lost before a job ID was saved, the example below cannot resolve that missing identity. Reconcile the original operation using its known transaction and authorization references.&lt;/p&gt;

&lt;p&gt;A timeout alone should never trigger a new trade.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Resume an existing observation job
&lt;/h2&gt;

&lt;p&gt;This example requires an observation job that already exists. It only polls that job; it does not create an authorization, sign a transaction, or broadcast one.&lt;/p&gt;

&lt;p&gt;Use Node.js 22 or later:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;priorseal-sdk
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; tsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save this as &lt;code&gt;resume-observation.mts&lt;/code&gt;:&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;createPriorSealClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;PriorSealApiError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;priorseal-sdk&lt;/span&gt;&lt;span class="dl"&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;jobId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PRIORSEAL_JOB_ID&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;trim&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;jobId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Set PRIORSEAL_JOB_ID to an existing observation job&lt;/span&gt;&lt;span class="dl"&gt;'&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;priorseal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createPriorSealClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://priorseal.xyz&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;job&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;priorseal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitForObservationJob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jobId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;timeoutMs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;pollIntervalMs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&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="na"&gt;jobId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;jobId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;jobState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;observation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;observation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;job&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="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="kc"&gt;null&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="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&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="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;PriorSealApiError&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;OBSERVATION_WAIT_TIMEOUT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Wait expired. Preserve this job ID for another observation attempt:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;jobId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exitCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;error&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;Run it with your saved job ID:&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;PRIORSEAL_JOB_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'your-existing-job-id'&lt;/span&gt; npx tsx resume-observation.mts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The polling interval and wait duration are example settings.&lt;/p&gt;

&lt;p&gt;If the wait expires again, preserve the same job ID. Schedule another observation attempt according to your application’s recovery policy.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Inspect the returned state
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;waitForObservationJob()&lt;/code&gt; returns when the job reaches &lt;code&gt;COMPLETED&lt;/code&gt;, &lt;code&gt;UNDETERMINED&lt;/code&gt;, or &lt;code&gt;FAILED&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Those are observation-job states. Your application must inspect the execution observation, available result, receipt, and error separately.&lt;/p&gt;

&lt;p&gt;A completed observation job does not by itself establish that a trade succeeded or complied with its authorization. A receipt may also require independent verification against trusted issuer keys and additional chain-state checks.&lt;/p&gt;

&lt;p&gt;Keep pending, reverted, reorged, and uncertain execution states explicit in your records.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Keep new execution behind its own authorization checks
&lt;/h2&gt;

&lt;p&gt;Recovering historical evidence does not extend an authorization window.&lt;/p&gt;

&lt;p&gt;If the business needs a new transaction, the executor must apply the relevant submission-time policy and obtain valid authorization for that action.&lt;/p&gt;

&lt;p&gt;The recovery worker above has a narrower responsibility: continue investigating an existing operation.&lt;/p&gt;

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

&lt;p&gt;Before deploying an agent, check that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Transaction and authorization identifiers survive a restart.&lt;/li&gt;
&lt;li&gt;Observation job IDs are saved as soon as they are returned.&lt;/li&gt;
&lt;li&gt;Client wait timeouts preserve the existing operation identity.&lt;/li&gt;
&lt;li&gt;Observation-job state and execution outcome are evaluated separately.&lt;/li&gt;
&lt;li&gt;New transactions require their own applicable policy and authorization checks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which part of your agent’s recovery state currently exists only in memory?&lt;/p&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/imokokok/PriorSeal/blob/main/sdk/README.md" rel="noopener noreferrer"&gt;PriorSeal SDK guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/imokokok/PriorSeal/blob/main/docs/runbooks/reliability.md" rel="noopener noreferrer"&gt;Integration and recovery checks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://priorseal.xyz/" rel="noopener noreferrer"&gt;PriorSeal&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>web3</category>
    </item>
  </channel>
</rss>
