Skip to content

Gate the 7 structural live-contract holdouts behind capability flags (clean-green subset) - #13

Merged
GraemeF merged 1 commit into
mainfrom
comms-e5vm.9
Jun 13, 2026
Merged

GraemeF merged 1 commit into
mainfrom
comms-e5vm.9

Conversation

@GraemeF

@GraemeF GraemeF commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #11 (comms-e5vm.5). The live zulip ContractFactory runs the
AgentComms contract against a real realm at 38/45. The 7 holdouts are
structural properties of any real Zulip — integer-second timestamps, and a
minter-side `is:mentioned` narrow keyed to the queue owner — not
factory-fixable, and all covered elsewhere (memory/fake + `realm.live.test.ts`).
They reported as 7 spurious failures: a broken window. This closes it.

Change

Two optional `ContractEnv` capability flags, following the existing
`newUnacquiredAdapter` omission pattern (optional field + early-return gate,
substrate-neutral — memory/fake leave them unset and run all 45):

  • `coarseTimestamps` gates the 4 range/replay tests that depend on distinct
    per-message timestamps (`range.since`/`range.until` inclusive, `since==until`
    single-timestamp, `replay(since) returns …`). The `…past every message`
    range/replay tests offset by an hour, so they run regardless.
  • `noSelfEventDelivery` gates the 3 event tests where a bot must observe its
    own post/mention on its own inbox within the contract's window
    (subscribe→post readiness, self-mention with/without explicit subscribe). The
    mention suppression test asserts non-delivery, so it runs regardless.

The live factory (`packages/zulip/contract.live.test.ts`) sets both `true`. The
flags are framed as substrate-capability declarations: a future
owned/ephemeral realm that delivers self-events would set
`noSelfEventDelivery: false` and recover those 3 — the gate reads "this
substrate can't, so skip," not "nobody runs this."

Verification

  • `bun run check` green (871 pass / 0 fail) — memory/fake contract unaffected,
    all 45 still run there.
  • `bun run test:live` green: 60 pass / 0 fail across 3 files against the real
    realm (`contract.live` went 38/7 → 45/0). No 429s.

Out of scope (sequenced after, in comms-e5vm.6): folding `realm.live.test.ts`
into the contract run / deleting the stateful fake.

The live zulip ContractFactory (comms-e5vm.5, PR #11) runs the AgentComms
contract against a real realm at 38/45. The 7 holdouts are structural
properties of any real Zulip — integer-second timestamps and a minter-side
is:mentioned narrow keyed to the queue owner — not factory-fixable, and all
covered elsewhere (memory/fake + realm.live.test.ts). They reported as 7
spurious failures: a broken window.

Add two optional ContractEnv capability flags, following the existing
newUnacquiredAdapter omission pattern (optional field, early-return gate,
substrate-neutral — memory/fake leave them unset and run all 45):

- coarseTimestamps gates the 4 range/replay tests that need distinct
  per-message timestamps.
- noSelfEventDelivery gates the 3 event tests where a bot must observe its
  own post/mention on its own inbox in the contract's window.

The live factory sets both true, so bun run test:live reports a clean green
applicable subset. A future owned/ephemeral realm that delivers self-events
flips noSelfEventDelivery false and recovers those 3.
@GraemeF
GraemeF merged commit d92f681 into main Jun 13, 2026
2 checks passed
@GraemeF
GraemeF deleted the comms-e5vm.9 branch June 13, 2026 10:20
GraemeF added a commit that referenced this pull request Jun 14, 2026
…ability + peer-mention + readiness/drain fixes (comms-e5vm.10) (#18)

Replaces PR #13's blanket live-contract gate (the `coarseTimestamps` +
`noSelfEventDelivery` ContractEnv flags) with the three triaged fixes
from
comms-e5vm.10, restoring real live coverage instead of skips.

## Treatments

1. **Coarse timestamps → a port capability.**
`AgentComms.capabilities.timestampGranularity`
(the resolution of the message-ordering model): Memory reports
`Duration.zero`
(its `ts` is a monotonic counter), Zulip reports `Duration.seconds(1)`
(integer
epoch seconds). The contract's `postSpaced` helper spaces the 4
range/replay
fixtures by one granularity unit, so they run at full assertion strength
on
**both** substrates. The `coarseTimestamps` gate is gone. (Production
rationale:
the gap-replay watermark dedups on `ts`, so "`ts` is not a unique key
below this
resolution" is knowledge a consumer should consult, not only a test
concern.)

2. **Readiness timing.** The subscribe→post→observe test's inline 2s
timeout
became a generous shared `EVENT_DELIVERY_DEADLINE` — the own-post
arrives on
   the live realm, just later than 2s.

3. **Self-mention → peer-mention.** The two mention-floor tests now have
a seeded
**peer** post the @-mention (sender ≠ self) via a new
`ContractEnv.peerPost`
hook (Memory injects a peer-authored message; Zulip posts through a
peer-bound
adapter). Self subscribes the channel (queue mode 'all') so the mention
surfaces on live Zulip, where a bound bot's minter-owned events queue
only
surfaces its own mentions in mode 'all'. The bare floor (mention without
a
channel subscribe) holds on Memory but not yet on Zulip; **comms-9usb**
tracks
   restoring it cross-substrate. The `noSelfEventDelivery` flag is gone.

## Also

- **Event-delivery robustness:** the positive event-delivery assertions
now
drain-until-match (`awaitEvent`) instead of positional `Queue.take`, so
a
duplicate / gap-replayed `message-posted` under 429 rate-limiting can't
break a
positional assertion (this was an intermittent live failure under load).
- The new port `capabilities` field is filled with an inert default at
the
  `completeAsSubstrate` test seam for the above-port MCP fakes.

## Validation

- `bun run check` green (866 tests).
- `bun run test:live` against a real Zulip realm: **60 pass / 0 fail** —
clean
  green, no gated-off holdouts.

`realm.live.test.ts` is unchanged; the fold-in is comms-e5vm.6.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant