{"id":1883,"date":"2026-09-10T08:24:43","date_gmt":"2026-09-10T15:24:43","guid":{"rendered":"https:\/\/www.kenwalger.com\/blog\/?p=1883"},"modified":"2026-09-10T08:24:46","modified_gmt":"2026-09-10T15:24:46","slug":"contract-discovery-bottleneck","status":"publish","type":"post","link":"https:\/\/www.kenwalger.com\/blog\/ai-engineering\/contract-discovery-bottleneck\/","title":{"rendered":"The Contract Discovery Bottleneck"},"content":{"rendered":"<p><em>AI can generate the code. We can verify the behavior. But who decides<br \/>\nwhat correct means?<\/em><\/p>\n<p>I <a href=\"https:\/\/www.kenwalger.com\/blog\/ai\/verification-bottleneck-ai-generated-software\/\">wrote recently<\/a> about a coding agent that built me a password reset<br \/>\nflow with a reset link that worked more than once.<\/p>\n<p>The bug survived because nobody had written down that a reset link<br \/>\nshould be single use. It was obvious right up until it wasn&#8217;t.<\/p>\n<p>My argument was that as AI makes implementation cheaper, verification<br \/>\nbecomes the bottleneck. The feature request said &#8220;build password reset.&#8221;<br \/>\nThe agent built password reset. The happy path worked. The tests passed.<br \/>\nThe implementation looked finished.<\/p>\n<p>What nobody had asked was whether the same reset link should work twice.<\/p>\n<p>So I added an independently written behavioral specification. The agent<br \/>\nimplemented against it. The verifier rejected the reusable token. The<br \/>\nagent fixed the implementation. The verifier passed it.<\/p>\n<p>That seemed like a useful pattern:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.kenwalger.com\/blog\/wp-content\/uploads\/2026\/09\/mermaid-diagram-2026-09-10-081104.png\" alt=\"Flowchart showing three sequential stages: a specification leads to an implementation, which leads to independent verification.\" \/><\/p>\n<p>Then I published the article, and the comments started finding things my<br \/>\nspecification didn&#8217;t say. That exposed a harder problem.<\/p>\n<h2>The specification wasn&#8217;t finished either<\/h2>\n<p>One reader asked what would happen if two password reset requests using<br \/>\nthe same token arrived at the same time.<\/p>\n<p>I hadn&#8217;t tested that. My test covered sequential reuse:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.kenwalger.com\/blog\/wp-content\/uploads\/2026\/09\/mermaid-diagram-2026-09-10-081312.png\" alt=\"Sequence diagram showing a user using a password reset token successfully, the server marking the token consumed, and a second attempt with the same token being rejected.\" \/><\/p>\n<p>But concurrent reuse is different:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.kenwalger.com\/blog\/wp-content\/uploads\/2026\/09\/mermaid-diagram-2026-09-10-081509.png\" alt=\"Sequence diagram showing two concurrent password reset requests. Request A validates the token and the server reports it unused. Request B validates the same token before A has consumed it, and the server again reports it unused. Both requests then consume the token and both resets succeed, producing two successful resets from a single link.\" \/><\/p>\n<p>Both requests check the token while it is still unused. Both proceed.<br \/>\nIf validation and consumption are not a single atomic operation, &#8220;single<br \/>\nuse&#8221; can still produce two successful resets.<\/p>\n<p>The original invariant was incomplete.<\/p>\n<p>That doesn&#8217;t make the specification useless. It makes the specification<br \/>\nprovisional.<\/p>\n<p>The interesting part is where the new knowledge goes.<\/p>\n<p>Once somebody discovers that &#8220;single use&#8221; also means competing attempts<br \/>\ncannot both succeed, that should stop being knowledge held by the person<br \/>\nwho noticed it. It belongs in the durable definition of correct<br \/>\nbehavior.<\/p>\n<p>The specification changes.<\/p>\n<p>Which means the loop is really closer to this:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.kenwalger.com\/blog\/wp-content\/uploads\/2026\/09\/mermaid-diagram-2026-09-10-081649.png\" alt=\"Flowchart showing a cycle. Human intent produces a provisional specification, which leads to an implementation, then to independent verification. Verification surfaces a newly discovered invariant, which feeds back into the specification, and the cycle repeats.\" \/><\/p>\n<p>That is messier than the first diagram.<\/p>\n<p>It is also much closer to engineering.<\/p>\n<h2>Separate tests can share the same mistake<\/h2>\n<p>Another reader described an integration builder where an agent wrote<br \/>\nboth a connector and the tests for that connector.<\/p>\n<p>Everything passed.<\/p>\n<p>Both were wrong.<\/p>\n<p>The connector and its tests encoded the same incorrect assumption about<br \/>\nOAuth token refresh. The mistake only surfaced when a customer&#8217;s token<br \/>\nexpired during a live session.<\/p>\n<p>The implementation and test suite were separate artifacts. They were not<br \/>\nindependent in the way that mattered.<\/p>\n<p>They shared an assumption.<\/p>\n<p>That distinction matters because &#8220;independent verification&#8221; can sound<br \/>\nlike an organizational property:<\/p>\n<ul>\n<li>different file<\/li>\n<li>different test suite<\/li>\n<li>different agent<\/li>\n<li>different step in the pipeline<\/li>\n<\/ul>\n<p>None of those necessarily provides independence.<\/p>\n<p>If the implementation and verifier derive their definition of correct<br \/>\nbehavior from the same incomplete prompt, they can agree perfectly and<br \/>\nstill be wrong.<\/p>\n<p>The student is no longer literally grading the same exam.<\/p>\n<p>Two students have simply studied from the same incorrect answer key.<\/p>\n<h2>Generating more tests doesn&#8217;t discover the missing rule<\/h2>\n<p>Another commenter asked whether property-based testing or giving an<br \/>\nagent an adversarial security persona might do a better job uncovering<br \/>\nthese unstated constraints.<\/p>\n<p>I think both are interesting, but they expose the same boundary.<br \/>\nProperty-based testing can explore a stated invariant extremely well.<\/p>\n<p>If I tell a framework:<\/p>\n<blockquote><p>\n  A successfully consumed reset token must never produce another<br \/>\n  successful reset.\n<\/p><\/blockquote>\n<p>it can generate combinations and sequences I would never think to<br \/>\nhand-author.<\/p>\n<p>But it cannot tell me that single use was a requirement if nobody<br \/>\nexpressed it.<\/p>\n<p>An adversarial agent has a similar problem. Asking a model to &#8220;try to<br \/>\nbreak this&#8221; may produce better tests than asking it to &#8220;write tests for<br \/>\nthis feature.&#8221; But if the adversary shares the same context, model<br \/>\nassumptions, and incomplete understanding of the requirement, how<br \/>\nindependent is it really?<\/p>\n<p>The question starts shifting from <em>who writes the tests?<\/em> to a more<br \/>\ndifficult one: <strong>where does the definition of correct behavior come<br \/>\nfrom?<\/strong><\/p>\n<h2>The verifier can be wrong too<\/h2>\n<p>One of the most interesting examples in the discussion came from a<br \/>\nverification harness rather than generated application code.<\/p>\n<p>A capability test timed out.<\/p>\n<p>The harness recorded the result as a failure.<\/p>\n<p>But a timeout did not establish that the capability failed. It<br \/>\nestablished that the harness did not obtain a result within the allotted<br \/>\ntime.<\/p>\n<p>Those are different claims.<\/p>\n<pre><code class=\"language-text\">FAILED\n<\/code><\/pre>\n<p>and<\/p>\n<pre><code class=\"language-text\">NOT TESTED\n<\/code><\/pre>\n<p>are not interchangeable.<\/p>\n<p>The verifier had turned an observation failure into an assertion about<br \/>\ncapability.<\/p>\n<p>That&#8217;s a useful warning for any architecture built around deterministic<br \/>\nverification: deterministic does not mean correct.<\/p>\n<p>A verifier can enforce the wrong invariant with absolute consistency.<\/p>\n<p>So can a specification.<\/p>\n<p>The goal isn&#8217;t to replace an unreliable agent with an infallible<br \/>\nverifier. There is no infallible verifier.<\/p>\n<p>The goal is to make the definition of correctness explicit enough that<br \/>\nit can be inspected, challenged, tested, and revised independently of<br \/>\nthe implementation.<\/p>\n<h2>So who writes the contract?<\/h2>\n<p>This was the question that pushed the argument furthest for me.<\/p>\n<p>If humans have to write complete behavioral specifications before agents<br \/>\ncan implement anything, haven&#8217;t we simply moved the bottleneck back to<br \/>\nhumans?<\/p>\n<p>Probably.<\/p>\n<p>And worse, the concurrency example demonstrates that humans don&#8217;t<br \/>\nnecessarily know the complete specification beforehand either.<\/p>\n<p>So &#8220;humans write the contract&#8221; isn&#8217;t much of an answer.<\/p>\n<p>An agent could propose it.<\/p>\n<p>That sounds circular at first. If the agent proposes the implementation<br \/>\nand proposes the contract, aren&#8217;t we back to the student grading the<br \/>\nexam?<\/p>\n<p>Only if proposing the contract and accepting the contract are the same<br \/>\noperation.<\/p>\n<p>They don&#8217;t have to be.<\/p>\n<p>An agent might generate a candidate operating contract:<\/p>\n<pre><code class=\"language-text\">reset token:\n  may be used once\n  competing attempts cannot both succeed\n  expires after N minutes\n  cannot authorize a different account\n<\/code><\/pre>\n<p>A human, another system, or some combination can then challenge that<br \/>\nmuch smaller artifact.<\/p>\n<p>The question being reviewed becomes:<\/p>\n<blockquote><p>\n  Is this an adequate definition of correct behavior?\n<\/p><\/blockquote>\n<p>rather than:<\/p>\n<blockquote><p>\n  Is this entire implementation correct?\n<\/p><\/blockquote>\n<p>That doesn&#8217;t solve the trust problem, but it reduces its surface area.<br \/>\nReviewing four lines is a different activity than reviewing four hundred.<br \/>\nOne is a conversation about intent. The other is an audit.<\/p>\n<p>But this runs straight back into the answer key problem.<\/p>\n<p>If the same model that will implement the feature also proposes the<br \/>\ncontract, they share assumptions. An agent that doesn&#8217;t know single use<br \/>\nmatters won&#8217;t propose single use as an invariant. It will produce a<br \/>\nconfident, well-formatted contract with the same hole in it, and now the<br \/>\nhole has been written down and approved.<\/p>\n<p>So accepting a contract has to do more than approve it. It has to<br \/>\nintroduce something the proposing agent didn&#8217;t have.<\/p>\n<p>That might be a person who has debugged this class of bug before. It<br \/>\nmight be a genuinely different model, though I&#8217;m unsure how much<br \/>\nindependence that buys. It might be a checklist derived from past<br \/>\nincidents, which is really institutional memory in a form an agent can<br \/>\nread. For a reset token, somebody&#8217;s list somewhere already says: single<br \/>\nuse, expiry, no account substitution, no concurrent success, session<br \/>\ninvalidation.<\/p>\n<p>The value comes from the independence of the source, not from the<br \/>\nceremony of the review.<\/p>\n<p>That may be a more tractable thing to build tooling around than<br \/>\nverification itself.<\/p>\n<h2>Maybe verification isn&#8217;t the deepest bottleneck<\/h2>\n<p>This is where the comments changed my framing.<\/p>\n<p>I started with:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.kenwalger.com\/blog\/wp-content\/uploads\/2026\/09\/mermaid-diagram-2026-09-10-081827.png\" alt=\"Flowchart showing the implementation bottleneck leading to the verification bottleneck, with a dashed arrow to a third stage labeled contract discovery, marked as an open question.\" \/><\/p>\n<p>I&#8217;m less sure that&#8217;s where it stops.<\/p>\n<p>Once implementation is cheap and verification is increasingly<br \/>\nautomatable, the harder problem may become discovering the invariants<br \/>\nworth verifying.<\/p>\n<p>Call it contract discovery.<\/p>\n<p>The requirement says:<\/p>\n<blockquote><p>\n  Reset my password.\n<\/p><\/blockquote>\n<p>Somebody has to discover:<\/p>\n<blockquote><p>\n  The link works once.\n<\/p><\/blockquote>\n<p>Then:<\/p>\n<blockquote><p>\n  Two concurrent attempts cannot both succeed.\n<\/p><\/blockquote>\n<p>Then perhaps:<\/p>\n<blockquote><p>\n  The token cannot authorize a different account.<\/p>\n<p>  A token issued before another successful reset may no longer be valid.<\/p>\n<p>  A reset invalidates existing sessions.\n<\/p><\/blockquote>\n<p>Some of those are product decisions. Some are security properties. Some<br \/>\nare implementation-independent behavioral invariants. Some may not apply<br \/>\nat all.<\/p>\n<p>The difficult work is deciding which ones belong to the definition of<br \/>\ncorrect.<\/p>\n<p>AI can help propose them.<\/p>\n<p>Property-based testing can explore them.<\/p>\n<p>Deterministic systems can enforce them.<\/p>\n<p>Production incidents will unfortunately discover some of them for us.<\/p>\n<p>But none of those eliminates the need to decide which claims actually<br \/>\ndefine correctness.<\/p>\n<h2>This gets harder when agents start acting<\/h2>\n<p>There is another reason I think this matters beyond generated code:<br \/>\nagents don&#8217;t just write things anymore. They call things.<\/p>\n<p>An agent calls an API. The response is <code>200<\/code>. The agent moves on.<\/p>\n<p>But a <code>200<\/code> says the request was processed. It doesn&#8217;t say the<br \/>\nconstraint the agent&#8217;s plan depended on was enforced. Maybe the call<br \/>\ntimed out after the write succeeded, so the retry performed the effect<br \/>\ntwice. Maybe the operation was legitimate the first time and should have<br \/>\nbeen rejected the second.<\/p>\n<p>That second one should look familiar. It&#8217;s the reset link, one layer<br \/>\nout.<\/p>\n<p>A bad implementation leaves an artifact somebody can inspect later.<\/p>\n<p>A bad tool call already happened.<\/p>\n<p>It sent the email. Charged the card. Revoked the access. Posted the<br \/>\nmessage.<\/p>\n<p>There is no diff to read.<\/p>\n<p>This is where the contract-discovery problem becomes more consequential.<br \/>\nThe system needs some definition of what the agent is permitted to cause<br \/>\nand what evidence would establish that the intended effect actually<br \/>\nhappened.<\/p>\n<p>I don&#8217;t think I have the architecture for that yet, but one boundary is<br \/>\nbecoming clearer:<\/p>\n<p><strong>The specification can be agent-readable without being agent-owned.<\/strong><\/p>\n<p>The agent should be able to see the invariant. Withholding the<br \/>\nrequirement only makes the work guesswork.<\/p>\n<p>But the agent shouldn&#8217;t be able to quietly redefine the invariant when<br \/>\nsatisfying it becomes inconvenient.<\/p>\n<p>Whatever accepts, stores, and evaluates the contract needs some<br \/>\nindependence from the reasoning that produced the implementation or<br \/>\naction.<\/p>\n<p>Where that boundary belongs remains a harder question.<\/p>\n<h2>The specification is durable because it can change<\/h2>\n<p>Calling the specification a durable artifact can sound like calling it<br \/>\nan immutable one.<\/p>\n<p>I don&#8217;t mean that.<\/p>\n<p>A durable specification should change when we learn something about what<br \/>\ncorrect behavior actually requires.<\/p>\n<p>What makes it durable is that the knowledge survives the implementation<br \/>\nthat taught us the lesson.<\/p>\n<p>The reset implementation may be rewritten next month.<\/p>\n<p>The framework may change.<\/p>\n<p>The agent may change.<\/p>\n<p>The database may change.<\/p>\n<p>But once we&#8217;ve established that two competing reset attempts cannot both<br \/>\nsucceed, that invariant should survive all of them.<\/p>\n<p>The same applies to an integration. Once a production failure teaches us<br \/>\nwhat token refresh must guarantee, that knowledge should not remain<br \/>\nattached to the incident report or the engineer who debugged it.<\/p>\n<p>It should become part of what &#8220;correct connector&#8221; means.<\/p>\n<p>The implementation may be disposable. The accumulated definition of<br \/>\ncorrectness is not.<\/p>\n<h2>I still don&#8217;t think this is solved<\/h2>\n<p>There are plenty of uncomfortable questions left.<\/p>\n<p>How independent does a verifier have to be?<\/p>\n<p>Can two agents using different prompts but the same underlying model<br \/>\nprovide meaningful independence?<\/p>\n<p>Who accepts an agent-proposed contract?<\/p>\n<p>How do you distinguish a genuine product invariant from an<br \/>\nimplementation detail that shouldn&#8217;t survive the current code?<\/p>\n<p>What happens when two valid invariants conflict?<\/p>\n<p>How do contracts evolve without quietly weakening previous guarantees?<\/p>\n<p>And how do we verify effects in external systems where state is delayed,<br \/>\npartially observable, or distributed?<\/p>\n<p>I don&#8217;t have good answers to all of those. That&#8217;s partly why I don&#8217;t<br \/>\nthink the answer is simply &#8220;write better tests.&#8221; The tests are<br \/>\ndownstream of the harder question.<\/p>\n<h2>Write down what you mean by correct<\/h2>\n<p>The original password-reset bug happened because a rule existed in<br \/>\nsomeone&#8217;s head and nowhere else.<\/p>\n<p>The comments on that experiment showed the next problem: writing down<br \/>\none rule doesn&#8217;t mean you&#8217;ve found all the others.<\/p>\n<p>That&#8217;s fine. The specification doesn&#8217;t have to arrive complete. It has<br \/>\nto provide somewhere for discovered invariants to go, and that somewhere<br \/>\nhas to be a place with a history: versioned, reviewable, and attached to<br \/>\nthe behavior rather than to the incident that revealed it.<\/p>\n<p>Maybe an agent proposes them. Maybe a human notices them. Maybe<br \/>\nproperty-based testing exposes them. Maybe an independent reviewer asks<br \/>\nthe annoying question nobody else asked. And sometimes production will<br \/>\nteach us the expensive way.<\/p>\n<p>The important part is that each discovery makes the durable definition<br \/>\nof correct behavior better.<\/p>\n<p>AI is making it remarkably cheap to turn an instruction into working<br \/>\ncode.<\/p>\n<p>Verification asks whether the code did what we said. Contract discovery<br \/>\nasks whether we said enough. I&#8217;m starting to think that&#8217;s the harder<br \/>\nproblem.<\/p>\n<a class=\"synved-social-button synved-social-button-share synved-social-size-48 synved-social-resolution-single synved-social-provider-facebook nolightbox\" data-provider=\"facebook\" target=\"_blank\" rel=\"nofollow\" title=\"Share on Facebook\" href=\"https:\/\/www.facebook.com\/sharer.php?u=https%3A%2F%2Fwww.kenwalger.com%2Fblog%2Fwp-json%2Fwp%2Fv2%2Fposts%2F1883&amp;t=The%20Contract%20Discovery%20Bottleneck&amp;s=100&amp;p[url]=https%3A%2F%2Fwww.kenwalger.com%2Fblog%2Fwp-json%2Fwp%2Fv2%2Fposts%2F1883&amp;p[images][0]=https%3A%2F%2Fwww.kenwalger.com%2Fblog%2Fwp-content%2Fuploads%2F2026%2F09%2Fmermaid-diagram-2026-09-10-081104.png&amp;p[title]=The%20Contract%20Discovery%20Bottleneck\" style=\"font-size: 0px;width:48px;height:48px;margin:0;margin-bottom:5px;margin-right:5px\"><img loading=\"lazy\" decoding=\"async\" alt=\"Facebook\" title=\"Share on Facebook\" class=\"synved-share-image synved-social-image synved-social-image-share\" width=\"48\" height=\"48\" style=\"display: inline;width:48px;height:48px;margin: 0;padding: 0;border: none;box-shadow: none\" src=\"https:\/\/www.kenwalger.com\/blog\/wp-content\/plugins\/social-media-feather\/synved-social\/image\/social\/regular\/96x96\/facebook.png\" \/><\/a><a class=\"synved-social-button synved-social-button-share synved-social-size-48 synved-social-resolution-single synved-social-provider-twitter nolightbox\" data-provider=\"twitter\" target=\"_blank\" rel=\"nofollow\" title=\"Share on Twitter\" href=\"https:\/\/twitter.com\/intent\/tweet?url=https%3A%2F%2Fwww.kenwalger.com%2Fblog%2Fwp-json%2Fwp%2Fv2%2Fposts%2F1883&amp;text=Hey%20check%20this%20out\" style=\"font-size: 0px;width:48px;height:48px;margin:0;margin-bottom:5px;margin-right:5px\"><img loading=\"lazy\" decoding=\"async\" alt=\"twitter\" title=\"Share on Twitter\" class=\"synved-share-image synved-social-image synved-social-image-share\" width=\"48\" height=\"48\" style=\"display: inline;width:48px;height:48px;margin: 0;padding: 0;border: none;box-shadow: none\" src=\"https:\/\/www.kenwalger.com\/blog\/wp-content\/plugins\/social-media-feather\/synved-social\/image\/social\/regular\/96x96\/twitter.png\" \/><\/a><a class=\"synved-social-button synved-social-button-share synved-social-size-48 synved-social-resolution-single synved-social-provider-reddit nolightbox\" data-provider=\"reddit\" target=\"_blank\" rel=\"nofollow\" title=\"Share on Reddit\" href=\"https:\/\/www.reddit.com\/submit?url=https%3A%2F%2Fwww.kenwalger.com%2Fblog%2Fwp-json%2Fwp%2Fv2%2Fposts%2F1883&amp;title=The%20Contract%20Discovery%20Bottleneck\" style=\"font-size: 0px;width:48px;height:48px;margin:0;margin-bottom:5px;margin-right:5px\"><img loading=\"lazy\" decoding=\"async\" alt=\"reddit\" title=\"Share on Reddit\" class=\"synved-share-image synved-social-image synved-social-image-share\" width=\"48\" height=\"48\" style=\"display: inline;width:48px;height:48px;margin: 0;padding: 0;border: none;box-shadow: none\" src=\"https:\/\/www.kenwalger.com\/blog\/wp-content\/plugins\/social-media-feather\/synved-social\/image\/social\/regular\/96x96\/reddit.png\" \/><\/a><a class=\"synved-social-button synved-social-button-share synved-social-size-48 synved-social-resolution-single synved-social-provider-linkedin nolightbox\" data-provider=\"linkedin\" target=\"_blank\" rel=\"nofollow\" title=\"Share on Linkedin\" href=\"https:\/\/www.linkedin.com\/shareArticle?mini=true&amp;url=https%3A%2F%2Fwww.kenwalger.com%2Fblog%2Fwp-json%2Fwp%2Fv2%2Fposts%2F1883&amp;title=The%20Contract%20Discovery%20Bottleneck\" style=\"font-size: 0px;width:48px;height:48px;margin:0;margin-bottom:5px;margin-right:5px\"><img loading=\"lazy\" decoding=\"async\" alt=\"linkedin\" title=\"Share on Linkedin\" class=\"synved-share-image synved-social-image synved-social-image-share\" width=\"48\" height=\"48\" style=\"display: inline;width:48px;height:48px;margin: 0;padding: 0;border: none;box-shadow: none\" src=\"https:\/\/www.kenwalger.com\/blog\/wp-content\/plugins\/social-media-feather\/synved-social\/image\/social\/regular\/96x96\/linkedin.png\" \/><\/a><a class=\"synved-social-button synved-social-button-share synved-social-size-48 synved-social-resolution-single synved-social-provider-mail nolightbox\" data-provider=\"mail\" rel=\"nofollow\" title=\"Share by email\" href=\"mailto:?subject=The%20Contract%20Discovery%20Bottleneck&amp;body=Hey%20check%20this%20out:%20https%3A%2F%2Fwww.kenwalger.com%2Fblog%2Fwp-json%2Fwp%2Fv2%2Fposts%2F1883\" style=\"font-size: 0px;width:48px;height:48px;margin:0;margin-bottom:5px\"><img loading=\"lazy\" decoding=\"async\" alt=\"mail\" title=\"Share by email\" class=\"synved-share-image synved-social-image synved-social-image-share\" width=\"48\" height=\"48\" style=\"display: inline;width:48px;height:48px;margin: 0;padding: 0;border: none;box-shadow: none\" src=\"https:\/\/www.kenwalger.com\/blog\/wp-content\/plugins\/social-media-feather\/synved-social\/image\/social\/regular\/96x96\/mail.png\" \/><\/a>","protected":false},"excerpt":{"rendered":"<p>AI can generate the code. We can verify the behavior. But who decides what correct means? I wrote recently about a coding agent that built me a password reset flow with a reset link that worked more than once. The bug survived because nobody had written down that a reset link should be single use. &hellip; <a href=\"https:\/\/www.kenwalger.com\/blog\/ai-engineering\/contract-discovery-bottleneck\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;The Contract Discovery Bottleneck&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"pmpro_default_level":"","_monsterinsights_skip_tracking":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[1807],"tags":[1942],"yst_prominent_words":[],"class_list":["post-1883","post","type-post","status-publish","format-standard","hentry","category-ai-engineering","tag-specifications","pmpro-has-access"],"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p8lx70-un","jetpack-related-posts":[],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/www.kenwalger.com\/blog\/wp-json\/wp\/v2\/posts\/1883","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.kenwalger.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.kenwalger.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.kenwalger.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.kenwalger.com\/blog\/wp-json\/wp\/v2\/comments?post=1883"}],"version-history":[{"count":2,"href":"https:\/\/www.kenwalger.com\/blog\/wp-json\/wp\/v2\/posts\/1883\/revisions"}],"predecessor-version":[{"id":1891,"href":"https:\/\/www.kenwalger.com\/blog\/wp-json\/wp\/v2\/posts\/1883\/revisions\/1891"}],"wp:attachment":[{"href":"https:\/\/www.kenwalger.com\/blog\/wp-json\/wp\/v2\/media?parent=1883"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.kenwalger.com\/blog\/wp-json\/wp\/v2\/categories?post=1883"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.kenwalger.com\/blog\/wp-json\/wp\/v2\/tags?post=1883"},{"taxonomy":"yst_prominent_words","embeddable":true,"href":"https:\/\/www.kenwalger.com\/blog\/wp-json\/wp\/v2\/yst_prominent_words?post=1883"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}