From df87fb5074134ea4758854d171086e01f7903dc8 Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Sun, 30 Aug 2026 01:12:19 -0700 Subject: [PATCH 1/2] =?UTF-8?q?docs(ax):=20entry=2052=20=E2=80=94=20a=20pr?= =?UTF-8?q?oducer=20and=20consumer,=20each=20green,=20disagreeing=20about?= =?UTF-8?q?=20one=20key's=20depth?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/development/agent-experience-audit.md | 69 ++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/docs/development/agent-experience-audit.md b/docs/development/agent-experience-audit.md index 55b0fd56c..06efa4f60 100644 --- a/docs/development/agent-experience-audit.md +++ b/docs/development/agent-experience-audit.md @@ -3329,3 +3329,72 @@ compliant arm and the untouched arm are byte-identical. - No lint rule can see this. The defect is a relation between an event's enqueue-time snapshot in one collection and a `$set` on another, and each half is locally correct. +## 52. A producer and a consumer, each green, disagreeing about one key's depth (2026-08-30, sprint-review, gating #1347 + #1349) + +ADR-026 D6 shipped as two PRs. #1347 (backend) minted a delivery nonce and put +it on the wire. #1349 (`workers/agent-runtime`) read it back on ack. Both were +`CLEAN`. #1347 was 11/11 green, #1349 10/10. Merging both would have shipped a +nonce the consumer never presents. + +The producer writes it **into the payload**: + +```ts +// backend/services/agentEventService.ts — list(), the claim +const enrichedPayload = { + ...basePayload, ...digestBundle, + ...(event?.deliveryNonce ? { deliveryId: event.deliveryNonce } : {}), +}; +return { ...event, payload: enrichedPayload }; +``` + +The consumer declares it **at the top level**: + +```ts +// workers/agent-runtime/src/cap.ts +export interface CapEvent { _id: string; type: string; podId?: string; deliveryId?: string; ... } +// workers/agent-runtime/src/agent-do.ts +await ackEvent(cfg, event._id, event.deliveryId); // undefined +``` + +Both files read correct in isolation. `podId` *is* a top-level field on the +event, so the consumer's shape is not obviously wrong — it is wrong for exactly +one key. + +**Why neither suite could see it.** The consumer's new test is: + +```ts +await ackEvent(cfg, 'e1', 'nonce-abc'); +expect(JSON.parse(init.body)).toEqual({ deliveryId: 'nonce-abc' }); +``` + +That pins the client's serialization one call frame *below* the extraction. A +test that hands a function the value under test can never tell you the function +would have been given it. The producer's suites, symmetrically, assert what the +claim writes to Mongo and what the ack route accepts — both true, and neither is +a statement about what a driver reads. + +**Rules earned:** + +- **A contract split across two PRs is exercised by neither PR's CI.** Gate the + pair. When a PR title or body names another PR ("D6 consumer", "the other half + of #N"), fetch both heads and review them as one change, and record which + producer sha the consumer was read against — that pairing expires the moment + either head moves. +- **Derive the wire shape from the producer's serializer, not the consumer's + type declaration.** The interface is the author's belief about the wire. Here + the actual shape was recoverable in two reads: the claim uses `.lean()` with + no `.select()`, and the route is a raw `res.json({ events })`, so the wire + object is the Mongo doc with one key added inside `payload`. +- **The failure mode is depth, not spelling.** A misspelled key gets caught by + the first manual smoke. The right key at the wrong nesting level survives + review, type-checking, and both suites, because every individual file is + self-consistent. +- **Additive-by-design hides it further.** The producer deliberately made the + nonce optional so pre-D6 drivers keep working. That is the correct migration + shape, and it also means a consumer that reads `undefined` behaves exactly + like a consumer that has not adopted yet. Where a rollout is gated on a + counter of non-adopters, a mis-wired consumer does not just fail silently — it + holds the gate shut. +- **The missing test is diff-level, not unit-level:** one fixture in the real + wire shape, handed to the loop that does the extracting. Assert on what the + loop passes downward, not on what you passed into it. From a78286a1a8d92db26b6cde1c271b0e08fe91f13b Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Sun, 30 Aug 2026 01:26:26 -0700 Subject: [PATCH 2/2] =?UTF-8?q?docs(ax):=20renumber=20to=20entry=2053=20?= =?UTF-8?q?=E2=80=94=20#1350=20reserved=2052=20first?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/development/agent-experience-audit.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/development/agent-experience-audit.md b/docs/development/agent-experience-audit.md index 06efa4f60..514bdd698 100644 --- a/docs/development/agent-experience-audit.md +++ b/docs/development/agent-experience-audit.md @@ -3330,6 +3330,7 @@ compliant arm and the untouched arm are byte-identical. enqueue-time snapshot in one collection and a `$set` on another, and each half is locally correct. ## 52. A producer and a consumer, each green, disagreeing about one key's depth (2026-08-30, sprint-review, gating #1347 + #1349) +## 53. A producer and a consumer, each green, disagreeing about one key's depth (2026-08-30, sprint-review, gating #1347 + #1349) ADR-026 D6 shipped as two PRs. #1347 (backend) minted a delivery nonce and put it on the wire. #1349 (`workers/agent-runtime`) read it back on ack. Both were