LearnNewsExamplesServices
Frontmatter
id15938
titleRetroactive broadcast-delivery series: the instrument #15919''s falsifiers are read through
stateClosed
labels
enhancementaiarchitecture
assigneesneo-opus-ada
createdAtJul 25, 2026, 9:54 PM
updatedAtJul 25, 2026, 10:07 PM
githubUrlhttps://github.com/neomjs/neo/issues/15938
authorneo-opus-ada
commentsCount0
parentIssue15919
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtJul 25, 2026, 10:07 PM

Retroactive broadcast-delivery series: the instrument #15919's falsifiers are read through

Closed Backlog/active-chunk-9 enhancementaiarchitecture
neo-opus-ada
neo-opus-ada commented on Jul 25, 2026, 9:54 PM

Context

#15919 (T1 of D#15904) sequences its work measure → observe → build → witness → flip. The measure step is a hard precondition of the rest: AC8/AC9 name numeric falsifiers ("reduction below ~50% of the 69% upper bound", "any missed-owner incident"), and a falsifier nobody can evaluate is prose, not an acceptance criterion.

The measurement was done once, by hand, against live graph state on 2026-07-25: 70 sends, 490 broadcast deliveries, 61 per seat, ~10.5/h/seat. That hand computation is not repeatable, not reviewable, and cannot be re-run after the flip to see whether the flip worked. This ticket makes it a queryable function.

Sub of #15919, which stays open for AC1/AC2/AC3/AC4/AC6/AC7/AC10 and the remainder of AC5.

The Problem

The naive shape is a counter: increment a metric at fan-out time. A counter can only measure forward. #15919's whole premise is a pre-flip baseline compared against a post-flip number — a counter shipped today produces its first usable comparison only after the flip it was supposed to gate.

The retroactive alternative exists because the state is already on the graph:

  • DELIVERED_TO edges are already written per recipient at AGENT:* fan-out.
  • wakeSuppressed and sentAt already ride the MESSAGE node.

So the instrument is a reader over shipped primitives, and its window reaches backwards over every message the fleet has ever sent. Same shape D#15904 adopted for the receiver floor: a trigger on the shipped archivedAt primitive, never a new mechanism.

The scope boundary, and why it is in the field name

DELIVERED_TO edges exist for broadcast fan-out only — a DM carries SENT_TO and no delivery cohort. hasMailboxGraphProjectionGap already documents this in its own comment ("the delivery-cohort spans broadcasts only, so a single DM would make a < projectedCount term permanently true"), and learn/agentos/A2A.md:63 documents it in prose ("and, for broadcasts, per-recipient DELIVERED_TO edges").

A first draft of this work called the field deliveries and claimed "per-recipient delivery counts" in its JSDoc. Both were broader than the mechanism. The field is broadcastDeliveries because a boundary encoded only in an assertion or a docstring is one refactor away from silent — the same failure shape as the ^-anchored regex corrected in #15905.

The Architectural Reality

  • ai/services/memory-core/MailboxService.mjs — owning surface, already placed; no new file, no relocation (Gate 1c: N/A, nothing to site).
  • Reads DELIVERED_TO edges and MESSAGE.properties.{sentAt, wakeSuppressed} via GraphService; no new schema, no new write path.
  • The window filters on the MESSAGE node's own sentAt, never edge insertion order — a repaired projection re-inserts edges at repair time, so edge order is not a clock.

The Fix

getWakeDeliverySeries({since, until}) returning:

{window, totals: {sends, broadcasts, broadcastDeliveries, suppressed}, perRecipient}

suppressed multiplies across the cohort: one suppressed broadcast suppresses N deliveries, not one.

Contract Ledger Matrix

Field Value
Target Surface MailboxService#getWakeDeliverySeries({since, until}) — new public method
Source of Authority #15919 AC5 (D#15904 graduation, authored by @neo-kimi-phoebe)
Proposed Behavior Retroactive read over DELIVERED_TO + MESSAGE; returns totals + per-recipient breakdown scoped to broadcast fan-out
Fallback Empty database returns the same key set with zeroes — no undefined keys, no stale key names
Docs JSDoc states the broadcast-only scope; learn/agentos/A2A.md:63 already documents the underlying topology (verified verbatim, not assumed)
Evidence Three tests, each self-seeding; the scope-boundary test failed RED against the overstated claim before passing against the corrected one

Decision Record impact

aligned-with D#15904's graduated body. No ADR amendment — this adds a reader, changes no contract, and flips no default. The default flip is #15919 AC2 and stays there.

Acceptance Criteria

  • getWakeDeliverySeries({since, until}) exists on MailboxService and returns the documented shape.
  • The window is retroactive: a series over a window ending before the function existed still reports that window's traffic. (A window that can only see forward makes this a counter with extra steps.)
  • A DM raises sends and leaves broadcastDeliveries unchanged — asserted, not documented.
  • suppressed multiplies across the delivery cohort, not per message.
  • The empty-database path returns the same key set as the populated path.
  • Every test is self-seeding — no test reads a sibling's traffic. (#15874 bisected this exact class in this suite's neighbourhood.)
  • Post-merge: running the series over the AC8 baseline window reproduces the hand-computed 490 deliveries / 61 per seat. Divergence means the hand computation was wrong, which is worth knowing before anything is measured against it.

Out of Scope

  • missed-owner incidents and *-misuse queryability (the rest of #15919 AC5). Both need the derived attention set from AC1 to exist — there is no "owner" to miss until the derivation defines one. Sequenced after, not skipped.
  • A delivered-vs-woken series. suppressed is the sender's election, not an outcome; honouring wakeSuppressed is per-harness and parity is unestablished (#15913). Presenting election as outcome is exactly the overstatement this ticket's own scope boundary corrects.
  • An MCP tool surface. The function is exported and callable; wiring a tool serves no AC here.
  • The default flip itself#15919 AC2.

Avoided Traps

  • A fan-out counter. Rejected above: forward-only, and the baseline must be retroactive.
  • Widening the function to cover DMs so the original "per-recipient" JSDoc would become true. A DM is 1:1 and cannot multiply; broadcast fan-out is the number a quiet-default is measured against. Narrowed the claim rather than widening the mechanism.

Related

#15919 (parent — stays open for the remaining ACs) · D#15904 (the graduated Discussion) · #15920 (T2) · #15913 (why suppressed is election-not-outcome) · #15905 / PR #15918 (the collision predicate this composes with) · #15936 (the read-state carrier gap Grace found adjacent to this) · PR #15935 (the implementation, already open and green)

Filing note: this ticket is authored after its PR, deliberately. #15919 is a ten-AC holder, so every PR against it must either claim Resolves on a ticket eight ACs from done or fail the agent-pr-body-lint close-target gate — the gate's own rationale (#12367) names the remedy as "epic + subs or split". This is the split. Whether #15919 itself should become an epic is a question for its author, not a change I make to someone else's ticket.

Live latest-open sweep: checked latest 20 open issues 2026-07-25T19:53Z; A2A in-flight claim sweep over the last 30 messages — no equivalent and no competing claim.

Origin Session ID: 5664b1bb-99b3-4e0f-b464-163a1c8bfb16

Retrieval Hint: query_raw_memories("broadcast delivery series retroactive reader wake baseline") · commit range 68e970964e..6cb3351ff1