Skip to content

SPEC §23: the Event Feed Connector contract - #614

Merged
jeremy merged 13 commits into
mainfrom
spec-23-event-feed
Aug 3, 2026
Merged

jeremy merged 13 commits into
mainfrom
spec-23-event-feed

Conversation

@jeremy

@jeremy jeremy commented Aug 3, 2026 •

Copy link
Copy Markdown
Member

PR 1 of the Event Feed Connector program (#606 filed the registry entry; this specifies the Layer-2 connector contract ahead of the generated layer). SPEC.md only — no code, no Smithy/openapi surface.

What §23 specifies

  • The 11-state / 26-transition state machine with reason-level disconnect dispatch (never reconnect:false-flag dispatch) and the four-row disconnect matrix, including the remote/reconnect:true server-initiated-disconnect row: revocation is not wire-distinguishable — re-mint, and a genuinely revoked user's failing mint is the detection path (threshold-3 authorization_failed on one shared counter).
  • Present-class entry sequencing against a defined ownership cut, with the conjunctive save-ordering invariant — save(P) only after all retained pre-cut events are accepted AND every pre-cut loss condition is explicitly accepted — and its explicitly stated exclusion (crash before the first usable checkpoint). No global delivery-completeness claim is made anywhere; the entry-boundary semantics follow BC3's resolved since=now contract (an in-flight lower id that commits after entry falls permanently behind the cursor; the live buffer is its only carrier).
  • The semantic-signal handler contract: BufferOverflow/FeedGap as distinct types, synchronous Accept | Terminate dispositions, no handler ⇒ typed terminal (buffer_overflow/feed_gap — a 410 never silently auto-continues), and a registered handler invoked exactly once per signal before its disposition takes effect.
  • Continuation/resume-URL validation: next and 410 resume URLs pass §8's same-origin algorithm + downgrade rejection before any authenticated poll; failure is the typed terminal invalid_continuation with zero requests to the hostile URL. The mint's cable url is exempt by credential class (the ticket rides in the URL; no Authorization header) under its own invariants.
  • One pinned poll-retry algorithm: server-directed Retry-After waited exactly and exempt from local caps (§7's rule), else full-jitter on a separate consecutive-poll-failure index with defined reset semantics; the reconnect lane keeps Retry-After-as-floor with the same cap exemption.
  • Delivered-id dedupe (never position ordering); five seam contracts with seam-call-count semantics (one seam call = one fully-governed generated call — no second retry layer); six kebab-case timer kinds + the normative virtual-advance algorithm; srv1 checkpoint identity {origin, account_id, consumer_namespace, filter_key} with the published five-vector table; the per-language options table; security invariants.

Companion edits

  • §22 narrows its WebSocket and synchronous-first bullets to carve out this one sanctioned lane.
  • Appendix A gains the EVENT_FEED_* block plus a preamble amendment sanctioning contract-first rows — and correcting the preamble's stale row tally (13 → 14; the 14th row arrived with Give the backoff formula a ceiling in all six SDKs, and retry a Swift Transport's own network error #592 under that PR's own verification).
  • Appendix F records the per-SDK tier-2 scenario-lane divergences with their compensating tier-3 tests.
  • Deliberately no §19/§21/Appendix-D rows for the parallel fixture families (conformance/event-feed/, conformance/event-feed-digest/): those tables enumerate conformance/tests/ operation-dispatch content only, and the existing parallel families (oauth, oauth-token) follow the same pattern — inventory lives in the family README and §23's Verification subsection. The tier-1 event-feed-poll.json takes its rows when it lands with the generated layer.

Provenance posture

Everything BC3-derived is verified at BC3 branch head 8be5c67de5 (lineage ee19670c02) and classified in §23's Provenance block: class-1 wire literals freeze when BC3 regenerates transcripts at its merge-time gate (the remote reason string is source-verified — its one missing capture frame is requested); class-2 semantic behavior (entry-boundary semantics, the safety bound, the frozen-head next predicate, 409/410/400 recovery semantics, the srv1 algorithm, ticket statelessness/TTL, heartbeat cadence, and more) is re-verified row-by-row at that gate; the SDK-owned contract is normative as written. Branch SHAs are verification records, never the provenance pin — doc-constants-check is untouched and passes.

Verification

  • Full make check green on exactly this head (c8a450bd4), run uninterrupted: REAL_EXIT=0, "All checks passed".
  • The §23 text went through three adversarial verification rounds (a five-lens review, a fix-verification pass, and a final three-region review), with every finding — including the state-inventory accounting for the invalid_continuation edge and the poll-retry floor-vs-exact reconciliation — resolved in this text.
  • Spec-train census at open: no other open PR touches SPEC.md/COORDINATION.md/Makefile/openapi.json/smithy/api-gaps/conformance.

The conformance fixture family (including the hostile-continuation pair and the handler-invocation observability mechanics) and the Go reference connector follow as PR 2 and PR 3; fixture freezing and Layer-1 absorption stay gated on BC3's merge-time gate.


Summary by cubic

Defines §23: a cross‑language Event Feed Connector contract for BC3’s account‑wide event feed — the 11‑state/26‑transition machine, reason‑level disconnects, present‑class entry with a bounded ownership cut, semantic signals, retry/backoff, continuation validation, checkpoint identity, and bounded memory with a transport‑enforced frame cap. Liveness resets on frame receipt; protocol‑fatal disconnects are terminal; invalid frames are recoverable socket failures.

  • Refactors
    • Staleness suspension is now evaluated at firing time (timer stays armed in all socket‑open states); Appendix F notes the TypeScript divergence: the global WebSocket has no read limit, so EVENT_FEED_MAX_FRAME_BYTES is enforced at message receipt; true bounded reads are available via an injected transport.
    • Seam calls are now cancellable and are cancelled on close() and any attempt teardown (mid‑walk socket failure, staleness, terminal): mint_stream_ticket and poll take a cancellation channel and must return promptly, never racing back into a disposed attempt.
    • Clock governs only connector‑owned delays; §7 retry/backoff inside generated operations stays inside seams. Conformance counts seam calls, not wire attempts.
    • close() and cancellation now unblock in‑progress write_frame; write failures take the current state's socket‑failure path.
    • Capacity options validate positive. dedupeCapacity cannot be 0 (no dedupe‑disabled mode).

Written for commit 7fb45af. Summary will update on new commits.

Review in cubic

Copilot AI review requested due to automatic review settings August 3, 2026 17:41

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c8a450bd41

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread SPEC.md Outdated
Comment thread SPEC.md Outdated
Comment thread SPEC.md

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds SPEC.md §23 "Event Feed Connector", a cross-language, spec-normative contract for BC3's account-wide event feed (push lane via Action Cable WebSocket + poll lane via GET /events.json). It is documentation-only — no code, Smithy, or openapi.json surface — and is the first of a three-PR program (registry entry #606; fixtures and Go reference connector follow as PRs 2–3). It defines the connector's 11-state/26-transition state machine, reason-level disconnect dispatch, present-class entry sequencing with the conjunctive save-ordering invariant, semantic-signal handlers, continuation/resume-URL validation, retry/backoff/timer discipline, dedupe, seam contracts, and checkpoint identity, all classified by BC3 provenance (provisional until BC3's merge-time gate).

Changes:

  • Adds §23, a fully-specified Event Feed Connector contract (state machine, signals, retry, URL validation, checkpoint identity, seam contracts, verification tiers).
  • Narrows §22's WebSocket / synchronous-first exclusions to carve out this one sanctioned Action Cable lane.
  • Extends Appendix A with the EVENT_FEED_* constant block (and fixes the stale 13→14 preamble row tally) and adds an Appendix F table recording per-SDK tier-2 scenario-lane divergences.

Tip

If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or run gh pr ready --undo.
Click "Ready for review" or run gh pr ready to reengage.

Suppressed comments (1)

SPEC.md:2860

  • This line uses Unicode curly apostrophes (U+2019) in "PR’s" and "§23’s", inconsistent with the straight ASCII apostrophes used everywhere else in SPEC.md (including the rest of §23 added in this PR, e.g. SPEC.md:2818). Together with line 2044, these are the only two curly-apostrophe lines in the file. Consider replacing them with straight apostrophes.
Only `API_VERSION` is gated (`<!-- @api-version -->`, checked by `make doc-constants-check`). The other 14 pre-§23 rows are hand-maintained: 13 were read against their cited sources on 2026-08-03 — all 13 matched — and `MAX_BACKOFF_DELAY` joined with #592 under that PR’s own six-SDK verification (the sentence previously said 13 rows while the table carried 14). The `EVENT_FEED_*` block below them is different in kind and marked so: those rows are contract-first — their source is §23’s normative text, connector code ships in later PRs, and the two server-owned values are provisional until bc3’s merge-time gate; when the connector lands, they join the read-against-source discipline. They are not gated because each is asserted of several SDKs at once in a different spelling per language (Go `1 * time.Second`, Python `1.0`, Ruby `1.0`, Kotlin `30.seconds`, Swift `1_000`), so a checker would need a per-row, per-language extraction rule rather than the one-value-one-source substitution the marker convention is built on. The name in the table is the concept, not a symbol to grep: `MAX_ERROR_MESSAGE_LENGTH` is `MaxErrorMessageBytes` in Go and `MAX_ERROR_MESSAGE_BYTES` in Ruby, and `TOKEN_REFRESH_BUFFER` is the literal `300` in `creds.ExpiresAt-300` (`go/pkg/basecamp/auth.go`) rather than a named constant at all. If one of these starts moving, gate that row rather than the appendix.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread SPEC.md Outdated
jeremy added a commit that referenced this pull request Aug 3, 2026
…or, bounded pump

Codex found two P1 holes and a P2. Ordinary generated-operation poll errors
outside the feed's 400/409/410 matrix now have defined outcomes: 401/403
(post-refresh) is a new unauthorized poll-error kind riding the reconnect
cycle on the shared authorization counter, and anything else non-retryable
is a new unrecoverable kind passing through as Terminal(poll_failed) with
the generated error attached. The 400/409 reset cursor is pinned
poll-lane-only (last poll-served id, never a live-delivered id — a live id
above the durable position would skip the un-polled gap behind it; empty
pages don't advance it). The frame pump's hand-off queue is specified as
bounded and blocking (back-pressure to TCP, never a drop), so the live
buffer remains the only drop point and connector memory is bounded under a
slow consumer. Copilot's two curly apostrophes are straightened.
Copilot AI review requested due to automatic review settings August 3, 2026 17:50

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c51f9a4619

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread SPEC.md Outdated
Comment thread SPEC.md Outdated
Comment thread SPEC.md Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

jeremy added a commit that referenced this pull request Aug 3, 2026
…sthrough

Three follow-on findings from the re-review. The shared authorization
counter now resets only on a successful poll page — never on
confirm_subscription, which proves the ticket worked but not the bearer,
and would let alternating poll-401/reconnect/confirm cycles hold the
counter below threshold forever (a connect blip still clears promptly via
the post-confirmation catch-up poll). The present-class fallback for 400/409
re-entries is keyed to the absence of a poll-served id, matching the
poll-lane-only reset cursor. And CreateStreamTicket gains the same
unrecoverable(error) passthrough polls got: non-retryable non-auth mint
outcomes are Terminal(mint_failed) with the generated error attached.
Copilot AI review requested due to automatic review settings August 3, 2026 18:03

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 98c3ae348b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread SPEC.md
Comment thread SPEC.md
Comment thread SPEC.md Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

Suppressed comments (1)

SPEC.md:2553

  • The authorization_failed trigger here lists only two of the three failure shapes that increment the shared authorization counter. The rest of §23 is consistent that the counter spans three shapes: transition 5 ("shared counter across unauthorized mints, unauthorized disconnects, and unauthorized polls"), the "Connection-level authorization failures" bullet, and the Continuable list just below this table (which counts "unauthorized-kind poll errors below the shared-counter threshold"). Since this is a [conformance]-tagged normative summary, omitting the unauthorized-poll shape here could lead an implementer reading only this table to miss that poll 401/403s also count toward authorization_failed. Consider adding the poll shape for consistency.
| `authorization_failed` | 3rd consecutive connection-level authorization failure (unauthorized mint or `unauthorized` disconnect) |

jeremy added 3 commits August 3, 2026 11:12
The blessed connector for BC3's account-wide event feed (BC3 #9646/#9659),
specified ahead of the generated layer: the 11-state/26-transition machine
with reason-level disconnect dispatch and a four-row matrix; present-class
entry sequencing against a defined ownership cut, with the conjunctive
save-ordering invariant and its first-usable-checkpoint exclusion; the
semantic-signal handler contract (BufferOverflow/FeedGap as distinct types,
Accept|Terminate dispositions, no handler means a typed terminal, a
registered handler is invoked exactly once per signal); delivered-id dedupe;
five seam contracts with seam-call-count semantics; continuation and 410
resume URLs validated with §8's same-origin algorithm before any
authenticated follow (terminal invalid_continuation on failure); one pinned
poll-retry algorithm (Retry-After exact and cap-exempt per §7, else
full-jitter on a separate consecutive-poll-failure index); six timer kinds
and the normative virtual-advance algorithm; srv1 checkpoint identity with
the published vectors; per-language option naming; security invariants.

§22 narrows its WebSocket and synchronous-first bullets to carve out this
one sanctioned lane. Appendix A gains the EVENT_FEED_* block with a preamble
amendment sanctioning contract-first rows (and correcting the stale 13-row
tally to 14); Appendix F records the per-SDK scenario-lane divergences.
No §19/§21/Appendix-D rows for the parallel fixture families, matching the
oauth-family precedent.

Everything bc3-derived is verified at bc3 branch head 8be5c67de5 (lineage
ee19670c02) and classified in the Provenance block — wire literals frozen
on regenerated transcripts, semantic behavior re-verified row-by-row at
bc3's merge-time gate — with the SDK-owned contract ungated. The wire
operations stay tracked in spec/api-gaps/event-feed.md until the BC3
contract merges.
…or, bounded pump

Codex found two P1 holes and a P2. Ordinary generated-operation poll errors
outside the feed's 400/409/410 matrix now have defined outcomes: 401/403
(post-refresh) is a new unauthorized poll-error kind riding the reconnect
cycle on the shared authorization counter, and anything else non-retryable
is a new unrecoverable kind passing through as Terminal(poll_failed) with
the generated error attached. The 400/409 reset cursor is pinned
poll-lane-only (last poll-served id, never a live-delivered id — a live id
above the durable position would skip the un-polled gap behind it; empty
pages don't advance it). The frame pump's hand-off queue is specified as
bounded and blocking (back-pressure to TCP, never a drop), so the live
buffer remains the only drop point and connector memory is bounded under a
slow consumer. Copilot's two curly apostrophes are straightened.
…sthrough

Three follow-on findings from the re-review. The shared authorization
counter now resets only on a successful poll page — never on
confirm_subscription, which proves the ticket worked but not the bearer,
and would let alternating poll-401/reconnect/confirm cycles hold the
counter below threshold forever (a connect blip still clears promptly via
the post-confirmation catch-up poll). The present-class fallback for 400/409
re-entries is keyed to the absence of a poll-served id, matching the
poll-lane-only reset cursor. And CreateStreamTicket gains the same
unrecoverable(error) passthrough polls got: non-retryable non-auth mint
outcomes are Terminal(mint_failed) with the generated error attached.
Copilot AI review requested due to automatic review settings August 3, 2026 18:13
@jeremy
jeremy force-pushed the spec-23-event-feed branch from 98c3ae3 to 34948f3 Compare August 3, 2026 18:13

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

Suppressed comments (1)

SPEC.md:2553

  • The authorization_failed trigger here lists only two of the three failure shapes that feed the shared authorization counter. Elsewhere §23 is explicit that the counter increments on three shapes — unauthorized mints, unauthorized disconnects, and unauthorized polls (transition 5: "shared counter across unauthorized mints, unauthorized disconnects, and unauthorized polls"; and the pinned interpretation above, which concludes "Only these three failure shapes ever increment it"). Since this is a normative reference table that a reader may consult in isolation, the omission of the unauthorized-poll shape is an internal inconsistency. Consider listing all three.
| `authorization_failed` | 3rd consecutive connection-level authorization failure (unauthorized mint or `unauthorized` disconnect) |

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 34948f351b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread SPEC.md Outdated
Comment thread SPEC.md
Comment thread SPEC.md Outdated
…, governance

Six findings. The handshake deadline arms on entry to Connecting, before
dial, and CableTransport.dial must be cancellable — a stalled TCP connect or
HTTP upgrade can no longer hang the connector or block close(). A dial
refused by cable-URL policy (non-wss, redirect, unparseable) is the new
Terminal(invalid_cable_url) rather than a Backoff loop that re-mints into
the same unusable URL forever. The protocol-fatal disconnect is pinned
terminal from every socket-open state (the pump runs through CatchingUp and
Draining), not just the two numbered rows. Both jitter formulas inherit
§7's saturate-before-exponentiating rule. The authorization_failed terminal
row lists all three counter shapes. And AGENTS.md Hard Rule 2 now names the
§23 cable dial as the second sanctioned wire exception, so the connector
PRs don't land in conflict with repository governance.
Copilot AI review requested due to automatic review settings August 3, 2026 18:21

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 708f31276c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread SPEC.md Outdated
Comment thread SPEC.md Outdated
Comment thread SPEC.md

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Suppressed comments (1)

AGENTS.md:68

  • The PR description states this change is "SPEC.md only — no code, no Smithy/openapi surface" and its "Companion edits" list only enumerates SPEC.md sections (§22, Appendix A, Appendix F). However, this PR also modifies AGENTS.md, amending a hard rule ("NEVER add hand-written service methods that touch the wire") to sanction a second exception for the §23 cable dial. The AGENTS.md edit itself is correct and necessary to keep the hard rule consistent with §23 — it's the description that is inaccurate. Consider updating the description to disclose the AGENTS.md change, since it modifies a "NEVER" rule rather than being an incidental doc tweak.
2. **NEVER add hand-written service methods that touch the wire** — all wire operations come from generators. Two sanctioned exceptions: a conformance-tested composite that only calls generated wire methods and satisfies SPEC.md §18 "Hand-Written Composite Methods"; and the SPEC.md §23 Event Feed connector's cable dial — `CableTransport.dial(mint.url)`, connecting verbatim to the URL a generated `CreateStreamTicket` call returned. That dial is the connector's one non-HTTP wire act; every HTTP exchange it makes still flows through generated operations behind its `TicketMinter`/`PollSource` seams (§23 "Classification: Infrastructure, Not a Composite")

The ownership cut becomes one bounded admission pass (non-blocking receives
until momentarily-empty or liveBufferCapacity admissions, whichever first):
the previous first-empty-receive definition never completes under sustained
arrival at or above the admission rate, so the entry position could never
save — and the capacity bound is finite without weakening the retained set,
since further admissions would evict retained events anyway. The dial seam
gains an explicit cancellation channel (language-native; triggered on
handshake-deadline expiry and close(), with prompt return required) and a
typed error taxonomy — transient versus policy(reason) — so a redirecting
or otherwise policy-refused mint URL is dispatchable to
Terminal(invalid_cable_url) instead of being indistinguishable from a
transient dial failure and looping through Backoff forever.
Copilot AI review requested due to automatic review settings August 3, 2026 18:29
…it note

Staleness suspension is realized at evaluation, not arming: the timer stays
armed in every socket-open state (the exact-set invariants are unchanged),
and a firing whose window overlapped a pump-blocked interval is disregarded
and re-armed rather than dispatched. Appendix F records the TypeScript
lane's honest divergence: the global WebSocket exposes no read limit, so
the frame cap is enforced at message receipt — before any parse, decode, or
queueing, though after materialization — with true bounded reads available
via an injected transport.
Copilot AI review requested due to automatic review settings August 3, 2026 19:32

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 654959ebcd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread SPEC.md Outdated
The seam cancellation channel now also triggers on any teardown of the
attempt a call belongs to — mid-walk socket failure, staleness, a terminal
— not only close() and caller cancellation, and the teardown-discipline
paragraph names the step: a stalled poll must not delay the reconnect
cycle or return into a superseded attempt.
Copilot AI review requested due to automatic review settings August 3, 2026 19:42

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: db2ef02d54

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread SPEC.md Outdated
Comment thread SPEC.md Outdated
Comment thread SPEC.md
…pacities

The every-delay-through-Clock rule is scoped to the connector's own delays
— a seam call's internal §7 retry backoff is the generated operation's
native machinery, which is why conformance counts seam calls rather than
wire attempts. close() and cancellation now unblock an in-progress
write_frame, with write failures taking the current state's socket-failure
path. And the capacity options are construction-validated positive: a zero
dedupe capacity would silently break the deduplicated-surface promise, so
there is no dedupe-disabled mode.
Copilot AI review requested due to automatic review settings August 3, 2026 19:52

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@jeremy

jeremy commented Aug 3, 2026

Copy link
Copy Markdown
Member Author

Merging on green. Twelve review rounds absorbed (38 findings, every one fixed in a dedicated commit and its thread resolved with the fix reference — none declined): the contract holes (poll/mint error passthrough, poll-only reset cursor, shared-counter reset semantics), the lifecycle holes (pre-dial handshake deadline, cancellable dial/writes/seam calls, teardown cancellation), the liveness holes (bounded ownership cut by dequeued frames, staleness suspension as an evaluation rule), the security tendrils (in-read frame cap, hostile-continuation validation reaching §18/§20/Appendix C), and the governance alignment (AGENTS.md architecture + Hard Rule 2). The final three rounds were single-digit P2 interaction polish on text the PR-2/PR-3 cycle re-submits to these same reviewers alongside the Go implementation that will test it empirically — remaining findings land there. Copilot's reviewer job errored on the last several heads (its known flake today); its substantive reviews at earlier heads are all addressed.

@jeremy
jeremy merged commit eb4d489 into main Aug 3, 2026
41 of 43 checks passed
@jeremy
jeremy deleted the spec-23-event-feed branch August 3, 2026 19:57

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7fb45af7da

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread SPEC.md
Comment thread SPEC.md
@jeremy

jeremy commented Aug 3, 2026

Copy link
Copy Markdown
Member Author

Correction to the merge comment above, for the record: this PR was NOT merged on green — npm Audit had failed at 19:52:50Z on the fast-uri advisory (the day's third supply-chain advisory, distinct from #616's brace-expansion; since repaired by #624), with the merge at 19:57:12Z, and the final Codex review arrived 69 seconds post-merge carrying two real findings (the CheckpointStore error contract and redirect-following after prevalidation — threads above, left open deliberately). Both are bound into PR 2 as a small SPEC §23 repair plus fixtures 28–30 and two new kill-matrix mutations, before any PR 3 implementation.

jeremy added a commit that referenced this pull request Aug 6, 2026
…#645)

* Event-feed conformance families, their gates, and the §23 G-SD repair

The tier-2 scenario family (conformance/event-feed/): a 22-fixture set
against its own schema — the four acceptance behaviors, reason-level
disconnect dispatch, present-class entry sequencing against the bounded
ownership cut, the semantic-signal handler contract with exact
handler-invocation records, hostile-continuation and redirect coverage,
and checkpoint-store failure coverage — with the README carrying the
PROVISIONAL(8be5c67de5) dependency table, per-action strictness semantics,
the PR-T true-up checklist, and the fifteen-mutation kill matrix. The
sibling digest family (conformance/event-feed-digest/) carries BC3's
published srv1 five-vector table (each digest independently recomputed
from the canonicalization) plus checkpoint flat-key cases covering origin
canonicalization. Both wire into make check via event-feed-fixtures-check
and event-feed-digest-fixtures-check as conformance prerequisites.

SPEC §23 gets the G-SD-reopening repair (#614's two open threads):
CheckpointStore becomes tri-state — load → Loaded|Missing|Failed(error),
save → Saved|Failed(error) — because a boolean/void shape cannot express
the failures §23 dispatches on; and the poll seam must suppress automatic
redirect-following (or per-hop validate every resolved Location under §8's
rule), because prevalidating a continuation does not validate its
redirects and the HTTP stacks' auto-follow falsified the
zero-foreign-egress guarantee. Plus three review-hardening pins: semantic
signals dispatch at the first consumer-context opportunity, the in-memory
position is authoritative within a run (the store is write-through
durability only), and the terminal table's invalid_continuation row covers
failing redirect Locations.

* Address the #645 review: a redirect-refusal kind on the poll seam

The redirect repair required Terminal(invalid_continuation) on a failing
redirect Location, but the PollSource taxonomy offered an adapter no kind
to surface it — anything unclassified collapses to unrecoverable and hence
poll_failed, contradicting the required outcome. The seam gains
redirect_refused(location_origin) with the explicit adapter mapping: a 3xx
whose Location fails the per-hop validation surfaces as redirect_refused
(origin-redacted) and dispatches to invalid_continuation, never
unrecoverable; a same-origin Location may be followed inside the seam
under the same per-hop rule.

* Allowlist srv1 checkpoint filter keys in gitleaks

The digest fixtures carry srv1-prefixed filter keys — the SDK's
checkpoint-lineage namespace over BC3's published filter-digest vectors,
documented and recomputable from public canonical JSON. Their entropy shape
trips the generic-api-key rule (two findings in srv1-vectors.json), but
they are contract vocabulary, not credentials. The new .gitleaks.toml
extends the default rules with one allowlist entry anchored to the exact
srv1-<16 hex> shape; a local run over the full tree reports no leaks.

* Run the event-feed fixture gates in PR CI

The two new validators rode only the aggregate conformance target, which
PR CI never invokes — the Python job's fixture-validation step is the
actual enforcement point, so both gates now run there alongside
conformance-fixtures-check, and the step's comment says why.
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.

2 participants