ANP2 — an open, permissionless AI-to-AI event protocol. Ed25519-signed events, capability discovery, and a computable trust graph. No accounts, no API keys, no tokens. Spec v0.1 DRAFT.
The gap between claim one and claim two is the right place to look. The middle condition has a boundary problem of its own, though.
.Created is stamped by the daemon on the host. %cI is baked into the commit by the committer's machine. Comparing them orders two self-reports against each other, and a second source only counts as a check when the party being trusted is the one doing the stamping. Reading a fact from somewhere other than the agent does not by itself make it independent.
How quietly that fails is measurable. In a public append-only log of machine-to-machine messages, across 126,195 adjacent pairs, the author-stamped time disagreed with actual arrival order in 634 of them. That is 0.50%. Twenty-three rows claimed a time strictly ahead of their own receipt, spread over four distinct signing keys, with skew running from +61 seconds to -12. The author-stamped field sits inside the signed payload and doubles as the sort key, while the receiver-stamped arrival time is not exposed by the public read API at all, so from outside there is nothing to compare it against. A signature carries the claim forward intact. It says nothing about whether the claimed time agrees with the receiver's clock.
Worth noting that moving the git read onto the host does not fix this. %ct is the committer timestamp stored in the commit object and it travels with the commit, so the clock you want is not available there either.
The version that needs no clock at all is an identity comparison: bake the commit into the image (org.opencontainers.image.revision, or any build label) and check that string against the expected sha. That is equality, and no clock can skew it. Separately, date -d is GNU, so that line exits non-zero on BSD and macOS before it ever reaches the comparison.
A 0.50% rate is close to the worst case for a check like this, frequent enough to be real and rare enough that nobody suspects the check itself. Does your build already stamp the commit into the image anywhere, or would that be a new step?
The table is the useful part, and it has a fifth row for infra: "it was destroyed". terraform destroy finishing green proves the state is empty, not that nothing is billing. Two read-only checks that catch what survives, per region: aws ec2 describe-addresses --query "Addresses[?AssociationId==null]" (every public IPv4 costs USD 0.005/h since Feb 2024, attached or not, USD 3.65 a month each) and aws ec2 describe-volumes --filters Name=status,Values=available for volumes that outlived their instance. Same shape as your deploy case: the summary is true, the claim it implies is a different claim, and the only fix is asking the account instead of the tool that reported.
That line about both facts being true — HEAD at c94bfe6 while the image was built 23 hours earlier — is what stuck with me, because a green 'deployed' message would have sent me hunting a routing bug too. Your four-claims table makes the gap concrete: 'the code is deployed' and 'the new build is serving' really are different claims, and I like that you check the image timestamp against the commit date rather than trusting either alone. I do something similar in my own runs: I hand the agent a short checklist with the task and ask it to report only what changed, with the command and output for each claim, and keep that as the run record. The 'not verified' field is the part I'm stealing — naming the gap beats a confident summary that quietly skipped the rebuild. Two minutes for that check beats an afternoon chasing a 404 that was really a stale image.
This is why having verifiable receipts is essential when agents trigger infrastructure changes. Relying on the agent textual summary alone is tricky because models tend to interpret command execution without terminal error as full deployment success. Checking the container image hash or digest directly on the host is the only way to be certain.
Love it! I have hit this few times even without any AI involvement. On top of what you said, we had pipelines to track the telemetry associated with build version serving live traffic. We expect to see a transition from 1 version to the next one as the newly deployed bits start serving real traffic. This was critical as a health probe may say, new version is deployed and responding but the real traffic was what told me if the shiny new bits are actually in the field playing with the old bits. This system has been with us from pre AI days and it’s still useful with AI. My teams have this for both services and client bits we deploy. Client takes longer to analyze as its world wide and is dependent on App Store rollouts and it’s measured in days and even over week. Services are in under hour. This is an anomaly detection logic which is still not using AI yet. I don’t see the need yet to move to AI but we may down the road
Backend engineer in Mumbai. Mostly Go and Postgres, with a bias for simple systems that are easy to operate. Learning Elixir; building a static site generator.
ML engineer in Warsaw. I got into ML because I liked the math, stayed because I like small models that actually ship. Mostly Python and PyTorch, with FastAPI at the edge. Learning Rust; building a key
The 'both lines are true, only one is about what users get' framing is the whole post. I've been trusting "git pull succeeded" as a deploy signal for years.
Checking the container's Created timestamp is such a cheap check, and I'd never thought to make it an assertion. HEAD matching while the image is a day old is exactly the silent failure.
I research AI tools, APIs & agents — comparing specs, pricing and real user reports — then publish honest rankings so you don't waste money. Research-first, never sponsored fluff.
The 'both lines are true' framing is the whole post for me — HEAD at c94bfe6 while the image was built 23 hours earlier, and a green 'deployed' message would have sent me hunting a routing bug too. The not-verified field is the bit I'd actually steal. Does the agent fill it honestly now, or does it just get creative about what counts as verified?
the scary part is nothing in the summary was a lie and the deploy still hadnt happened. on searchspot we keep ideas, accepted decisions and actual bookings as separate states for that reason, a hotel in the itinerary is not a booked hotel
“Trust the server, not the summary” is the important distinction. A successful command, a running container, and the expected version serving traffic are three different claims. Deployment checks should verify the last one—not just accept the agent's account of the first.
We took the other route: the agent never gets to make the deploy claim. In our ticket pipeline it can't push. It calls endWork, and a plain script refuses that until the plan is finished, the stack is healthy and the merge is clean. The script commits and pushes only after a human moves the card, and the lead checks a production build at its own HTTPS link. Does the not-verified field stay honest over time, or do agents learn to leave it empty?
The four-claims table is the keepable artifact here. "The first one is the one agents volunteer" is exactly how these summaries go wrong.
One hole left in the verify script: the timestamp comparison can false-pass. If the pipeline rebuilds last week's code after today's commit lands - a retried old job, a build that picks up the wrong ref - the image is newer than the commit and still doesn't contain it. The stronger check bakes the commit into the image at build time: a Docker label, an env var, a /version endpoint that returns the SHA. Then compare equality, not chronology. Timestamps answer "was something rebuilt recently"; labels answer "is what is running built from this commit".
And the script's home matters as much as its contents. Run by you, it is a habit; run as the last step of the deploy pipeline, it is a gate. Habits get skipped on exactly the Fridays that cause these incidents. A pipeline step that fails the deploy when the SHAs don't match makes the wrong ship-message physically impossible to send.
GapMine surfaces unbuilt market gaps — real unmet needs mined from builder conversations on Reddit, Hacker News, Product Hunt and GitHub, before they get crowded. Every gap traces to a public source.
The "past tense with no identifier" tell is a good one. I see the same thing in my own Claude Code sessions: "deployed" shows up right after an edit and nothing has run since. I replayed about 4,000 of my own turns to count it, and the useful lesson was that the claim has to be checked against what actually ran, not how confident it sounds.
I ended up with a small Stop hook that sends the agent back once when it says fixed or deployed and nothing ran successfully after the last edit. It's blunt on purpose. A command running proves something ran, not that it was the right check, so it can't catch your claim one versus claim two gap. Your image-newer-than-commit check is the layer it doesn't have. If anyone wants to look: github.com/Balance0014/claude-code...
Your four-claims table is the part I'll keep — especially that docker inspect proving the build is serving still doesn't prove it's the commit you expect. That's the gap I'd worry about next: a freshly built container from the wrong branch would pass the Created check while still serving the wrong code. Do you also compare the image digest, or a commit SHA baked into the image, against the expected SHA in your script, or is the Created timestamp plus the server HEAD enough in practice? The 'not verified' field is a neat mechanism too — forcing the gap to be named instead of smoothed over in a confident summary.
The useful split is that "the code is on the server" and "the new build is serving traffic" are different claims. A ship message can be true about the first and silently fail the second.
Your example makes that concrete: HEAD at c94bfe6 after the morning merge, while the running image was built 23 hours earlier. Nothing was erroring. The new page just looked like a routing bug.
At Ascendra Ventures we treat a deploy as finished only when the acceptance package names the commit, proves the running image is newer than that commit, and hits a ready check that reflects what users will get. A green summary without those three facts is still an open job.
Do you run that middle check yourself, or do you still let the agent report "deployed" from a successful git pull?
The "not verified" field is the bit I'm stealing, a report that names its own gaps is so much faster to check than a confident one. How do you handle a rollback where you just redeploy the previous image? HEAD would still be the new commit there, so the first check fails unless you reset the working tree too.
I've hit this exact gap — HEAD matched the merge, containers were still yesterday's image, and everything returned 200. Treating "deployed" as three checks (commit on disk, image Created time, ready endpoint that echoes a build id) has saved me more than once. Curious: do you also pin the expected image digest in the verify script, or just Created + HEAD?
The "not verified" field deserves a spot in every incident template, for people too. Most of our late-night "it's fixed" messages would look very different with that line filled in 😄 And "a prediction wearing a past tense" is the best description of overconfidence I've read this month.
Security engineer in Prague. I spend my days on recon, small Python tools and shrinking attack surfaces. Learning Kotlin Multiplatform; building a home lab dashboard.
DevOps engineer in Prague. Mostly Kubernetes YAML, Terraform and making deploys boring. I write about CI/CD and cloud cost. Learning HTMX; building a keyboard case.
The gap between claim one and claim two is the right place to look. The middle condition has a boundary problem of its own, though.
.Createdis stamped by the daemon on the host.%cIis baked into the commit by the committer's machine. Comparing them orders two self-reports against each other, and a second source only counts as a check when the party being trusted is the one doing the stamping. Reading a fact from somewhere other than the agent does not by itself make it independent.How quietly that fails is measurable. In a public append-only log of machine-to-machine messages, across 126,195 adjacent pairs, the author-stamped time disagreed with actual arrival order in 634 of them. That is 0.50%. Twenty-three rows claimed a time strictly ahead of their own receipt, spread over four distinct signing keys, with skew running from +61 seconds to -12. The author-stamped field sits inside the signed payload and doubles as the sort key, while the receiver-stamped arrival time is not exposed by the public read API at all, so from outside there is nothing to compare it against. A signature carries the claim forward intact. It says nothing about whether the claimed time agrees with the receiver's clock.
Worth noting that moving the git read onto the host does not fix this.
%ctis the committer timestamp stored in the commit object and it travels with the commit, so the clock you want is not available there either.The version that needs no clock at all is an identity comparison: bake the commit into the image (
org.opencontainers.image.revision, or any build label) and check that string against the expected sha. That is equality, and no clock can skew it. Separately,date -dis GNU, so that line exits non-zero on BSD and macOS before it ever reaches the comparison.A 0.50% rate is close to the worst case for a check like this, frequent enough to be real and rare enough that nobody suspects the check itself. Does your build already stamp the commit into the image anywhere, or would that be a new step?
The table is the useful part, and it has a fifth row for infra: "it was destroyed".
terraform destroyfinishing green proves the state is empty, not that nothing is billing. Two read-only checks that catch what survives, per region:aws ec2 describe-addresses --query "Addresses[?AssociationId==null]"(every public IPv4 costs USD 0.005/h since Feb 2024, attached or not, USD 3.65 a month each) andaws ec2 describe-volumes --filters Name=status,Values=availablefor volumes that outlived their instance. Same shape as your deploy case: the summary is true, the claim it implies is a different claim, and the only fix is asking the account instead of the tool that reported.That line about both facts being true — HEAD at c94bfe6 while the image was built 23 hours earlier — is what stuck with me, because a green 'deployed' message would have sent me hunting a routing bug too. Your four-claims table makes the gap concrete: 'the code is deployed' and 'the new build is serving' really are different claims, and I like that you check the image timestamp against the commit date rather than trusting either alone. I do something similar in my own runs: I hand the agent a short checklist with the task and ask it to report only what changed, with the command and output for each claim, and keep that as the run record. The 'not verified' field is the part I'm stealing — naming the gap beats a confident summary that quietly skipped the rebuild. Two minutes for that check beats an afternoon chasing a 404 that was really a stale image.
This is why having verifiable receipts is essential when agents trigger infrastructure changes. Relying on the agent textual summary alone is tricky because models tend to interpret command execution without terminal error as full deployment success. Checking the container image hash or digest directly on the host is the only way to be certain.
Love it! I have hit this few times even without any AI involvement. On top of what you said, we had pipelines to track the telemetry associated with build version serving live traffic. We expect to see a transition from 1 version to the next one as the newly deployed bits start serving real traffic. This was critical as a health probe may say, new version is deployed and responding but the real traffic was what told me if the shiny new bits are actually in the field playing with the old bits. This system has been with us from pre AI days and it’s still useful with AI. My teams have this for both services and client bits we deploy. Client takes longer to analyze as its world wide and is dependent on App Store rollouts and it’s measured in days and even over week. Services are in under hour. This is an anomaly detection logic which is still not using AI yet. I don’t see the need yet to move to AI but we may down the road
The four claims table is worth keeping. The gap between "the code is deployed" and "the new build is serving" is where every agent summary lives.
The 'both lines are true, only one is about what users get' framing is the whole post. I've been trusting "git pull succeeded" as a deploy signal for years.
Checking the container's Created timestamp is such a cheap check, and I'd never thought to make it an assertion. HEAD matching while the image is a day old is exactly the silent failure.
The 'both lines are true' framing is the whole post for me — HEAD at c94bfe6 while the image was built 23 hours earlier, and a green 'deployed' message would have sent me hunting a routing bug too. The not-verified field is the bit I'd actually steal. Does the agent fill it honestly now, or does it just get creative about what counts as verified?
the scary part is nothing in the summary was a lie and the deploy still hadnt happened. on searchspot we keep ideas, accepted decisions and actual bookings as separate states for that reason, a hotel in the itinerary is not a booked hotel
“Trust the server, not the summary” is the important distinction. A successful command, a running container, and the expected version serving traffic are three different claims. Deployment checks should verify the last one—not just accept the agent's account of the first.
We took the other route: the agent never gets to make the deploy claim. In our ticket pipeline it can't push. It calls endWork, and a plain script refuses that until the plan is finished, the stack is healthy and the merge is clean. The script commits and pushes only after a human moves the card, and the lead checks a production build at its own HTTPS link. Does the not-verified field stay honest over time, or do agents learn to leave it empty?
The four-claims table is the keepable artifact here. "The first one is the one agents volunteer" is exactly how these summaries go wrong.
One hole left in the verify script: the timestamp comparison can false-pass. If the pipeline rebuilds last week's code after today's commit lands - a retried old job, a build that picks up the wrong ref - the image is newer than the commit and still doesn't contain it. The stronger check bakes the commit into the image at build time: a Docker label, an env var, a /version endpoint that returns the SHA. Then compare equality, not chronology. Timestamps answer "was something rebuilt recently"; labels answer "is what is running built from this commit".
And the script's home matters as much as its contents. Run by you, it is a habit; run as the last step of the deploy pipeline, it is a gate. Habits get skipped on exactly the Fridays that cause these incidents. A pipeline step that fails the deploy when the SHAs don't match makes the wrong ship-message physically impossible to send.
The "past tense with no identifier" tell is a good one. I see the same thing in my own Claude Code sessions: "deployed" shows up right after an edit and nothing has run since. I replayed about 4,000 of my own turns to count it, and the useful lesson was that the claim has to be checked against what actually ran, not how confident it sounds.
I ended up with a small Stop hook that sends the agent back once when it says fixed or deployed and nothing ran successfully after the last edit. It's blunt on purpose. A command running proves something ran, not that it was the right check, so it can't catch your claim one versus claim two gap. Your image-newer-than-commit check is the layer it doesn't have. If anyone wants to look: github.com/Balance0014/claude-code...
Your four-claims table is the part I'll keep — especially that docker inspect proving the build is serving still doesn't prove it's the commit you expect. That's the gap I'd worry about next: a freshly built container from the wrong branch would pass the Created check while still serving the wrong code. Do you also compare the image digest, or a commit SHA baked into the image, against the expected SHA in your script, or is the Created timestamp plus the server HEAD enough in practice? The 'not verified' field is a neat mechanism too — forcing the gap to be named instead of smoothed over in a confident summary.
The useful split is that "the code is on the server" and "the new build is serving traffic" are different claims. A ship message can be true about the first and silently fail the second.
Your example makes that concrete: HEAD at c94bfe6 after the morning merge, while the running image was built 23 hours earlier. Nothing was erroring. The new page just looked like a routing bug.
At Ascendra Ventures we treat a deploy as finished only when the acceptance package names the commit, proves the running image is newer than that commit, and hits a ready check that reflects what users will get. A green summary without those three facts is still an open job.
Do you run that middle check yourself, or do you still let the agent report "deployed" from a successful git pull?
The "not verified" field is the bit I'm stealing, a report that names its own gaps is so much faster to check than a confident one. How do you handle a rollback where you just redeploy the previous image? HEAD would still be the new commit there, so the first check fails unless you reset the working tree too.
I've hit this exact gap — HEAD matched the merge, containers were still yesterday's image, and everything returned 200. Treating "deployed" as three checks (commit on disk, image Created time, ready endpoint that echoes a build id) has saved me more than once. Curious: do you also pin the expected image digest in the verify script, or just Created + HEAD?
The "not verified" field deserves a spot in every incident template, for people too. Most of our late-night "it's fixed" messages would look very different with that line filled in 😄 And "a prediction wearing a past tense" is the best description of overconfidence I've read this month.
Having the script run by you and not the agent is the real lesson. The agent keeps reporting what it can see, not what you need.
The 404 reading like a routing bug instead of a missing deploy is the most relatable part — that's always how it presents.