Transfer independently black-box-verified server behavior from a source-assisted research phase conducted outside this repository. Only a sanitizer-candidate report of black-box findings and the packet captures it referenced were admitted; no upstream source, tests, history, harnesses, build trees, result files or source-assisted analysis crossed the boundary.
New upstream robustness defect: when an OPEN requests timestamps, omits the Clock parameter, and server restriction leaves StampAt non-none, upstream accepts the OPEN with a valid token and no Clock echoed, then the first ECHO terminates the server process. A tested no-timestamp server policy instead restricts StampAt to none and serves the session normally. An explicit Clock=0 is instead rejected at OPEN, so parameter presence is externally meaningful. This is recorded as an observed defect with a clean-server robustness recommendation; the implementation policy is deliberately left open.
Strengthened from thin or single-point evidence:
idle expiry has an observed additive ~5 s grace across the tested timeout values;
maximum-duration enforcement has an observed additive ~2 s grace from the first served ECHO;
a rate-limited request is the only tested drop class that extends the observed idle lifetime while advancing neither receive count nor window;
several tested post-deadline packet classes can consume an expired session's final usable lookup before the legitimate client's request;
reply sizing is byte-exactly capped at MTU on the tested 1500- and 1280-byte interfaces, while loopback was only demonstrated unclamped through 8000 bytes before the host's separate outbound-datagram ceiling intervenes;
the default fill phase continues across the sessions and IPv4/IPv6 listeners tested, without implying a universal process-wide implementation;
DSCP marking follows the session across interleaved traffic, OPEN replies remain unmarked, and server-initiated close replies retain the session mark.
New parser and negotiation edges include repeated known tags being last-valid-wins; invalid duplicate evidence is limited to Duration in both orders and invalid-second Clock/ServerFill forms, with other orders and parameters unspecified; unknown tag values being accepted in the tested varint form, negative Length negotiation behavior, and the distinction between omitted and explicitly-zero parameter values.
The review pass also reconciles the client and server specifications around maximum-duration timing, tightens evidence attribution for DSCP and MTU observations, and removes unsupported implementation prescriptions from the fill findings.
Host- and environment-specific figures are labelled as such throughout. Upstream defects and quirks are not promoted to interoperability requirements, black-box inferences are explicitly marked, and no production implementation policy is chosen here.
Documentation and sanitized packet evidence only; no production code changed.
Transfer independently black-box-verified server behavior from a source-assisted research phase conducted outside this repository. Only a sanitizer-candidate report of black-box findings and the packet captures it referenced were admitted; no upstream source, tests, history, harnesses, build trees, result files or source-assisted analysis crossed the boundary.
New upstream robustness defect: when an OPEN requests timestamps, omits the Clock parameter, and server restriction leaves StampAt non-none, upstream accepts the OPEN with a valid token and no Clock echoed, then the first ECHO terminates the server process. A tested no-timestamp server policy instead restricts StampAt to none and serves the session normally. An explicit `Clock=0` is instead rejected at OPEN, so parameter presence is externally meaningful. This is recorded as an observed defect with a clean-server robustness recommendation; the implementation policy is deliberately left open.
Strengthened from thin or single-point evidence:
- idle expiry has an observed additive ~5 s grace across the tested timeout values;
- maximum-duration enforcement has an observed additive ~2 s grace from the first **served** ECHO;
- a rate-limited request is the only tested drop class that extends the observed idle lifetime while advancing neither receive count nor window;
- several tested post-deadline packet classes can consume an expired session's final usable lookup before the legitimate client's request;
- reply sizing is byte-exactly capped at MTU on the tested 1500- and 1280-byte interfaces, while loopback was only demonstrated unclamped through 8000 bytes before the host's separate outbound-datagram ceiling intervenes;
- the default fill phase continues across the sessions and IPv4/IPv6 listeners tested, without implying a universal process-wide implementation;
- DSCP marking follows the session across interleaved traffic, OPEN replies remain unmarked, and server-initiated close replies retain the session mark.
New parser and negotiation edges include repeated known tags being last-valid-wins; invalid duplicate evidence is limited to Duration in both orders and invalid-second Clock/ServerFill forms, with other orders and parameters unspecified; unknown tag values being accepted in the tested varint form, negative Length negotiation behavior, and the distinction between omitted and explicitly-zero parameter values.
The review pass also reconciles the client and server specifications around maximum-duration timing, tightens evidence attribution for DSCP and MTU observations, and removes unsupported implementation prescriptions from the fill findings.
Host- and environment-specific figures are labelled as such throughout. Upstream defects and quirks are not promoted to interoperability requirements, black-box inferences are explicitly marked, and no production implementation policy is chosen here.
Documentation and sanitized packet evidence only; no production code changed.
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".
### 💡 Codex Review
Here are some automated review suggestions for this pull request.
**Reviewed commit:** `b3b754075b`
<details> <summary>ℹ️ About Codex in GitHub</summary>
<br/>
[Your team has set up Codex to review pull requests in this repo](https://chatgpt.com/codex/cloud/settings/general). 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".
</details>
Describe the open reply rather than a normal session
For an open with non-none StampAt and no Clock, this row says the session is answered normally while immediately stating that its first echo is fatal. The report and behavioral vector establish that only the open request is answered normally; the resulting session is unusable. Reword this to say the open is answered normally so the admission table does not contradict the documented defect.
**<sub><sub></sub></sub> Describe the open reply rather than a normal session**
For an open with non-none `StampAt` and no `Clock`, this row says the session is answered normally while immediately stating that its first echo is fatal. The report and behavioral vector establish that only the open request is answered normally; the resulting session is unusable. Reword this to say the open is answered normally so the admission table does not contradict the documented defect.
AGENTS.md reference: [AGENTS.md:L20-L23](https://github.com/Lochnair/irtt-rs/blob/b3b754075b850acc6b26dfa36d9ad24ced0a588f/AGENTS.md#L20-L23)
Useful? React with 👍 / 👎.
Present-zero forms do exist in the request direction: this same section discusses an explicit Clock = 0, the admission table accepts Length = 0 and DSCP = 0, and the new clock-absent capture includes an explicit zero Length tag. Only restricted zero values in open replies are omitted, so narrow this sentence to the reply direction rather than telling decoders that no request can encode a present zero.
**<sub><sub></sub></sub> Preserve present-zero request forms**
Present-zero forms do exist in the request direction: this same section discusses an explicit `Clock = 0`, the admission table accepts `Length = 0` and `DSCP = 0`, and the new clock-absent capture includes an explicit zero Length tag. Only restricted zero values in open replies are omitted, so narrow this sentence to the reply direction rather than telling decoders that no request can encode a present zero.
AGENTS.md reference: [AGENTS.md:L20-L23](https://github.com/Lochnair/irtt-rs/blob/b3b754075b850acc6b26dfa36d9ad24ced0a588f/AGENTS.md#L20-L23)
Useful? React with 👍 / 👎.
The loopback result cannot establish a cap at its exact 16384-byte MTU: the table only exercises lengths through 8000, while Section 22.1 says the host begins terminating the server around 9300, well before a reply can reach the loopback MTU. The evidence therefore demonstrates an exact cap for the 1500- and 1280-byte interfaces and only a lower bound on loopback; revise the three-interface claim so the verified baseline does not present the unobservable 16384 boundary as measured.
**<sub><sub></sub></sub> Limit the exact MTU claim to measured interfaces**
The loopback result cannot establish a cap at its exact 16384-byte MTU: the table only exercises lengths through 8000, while Section 22.1 says the host begins terminating the server around 9300, well before a reply can reach the loopback MTU. The evidence therefore demonstrates an exact cap for the 1500- and 1280-byte interfaces and only a lower bound on loopback; revise the three-interface claim so the verified baseline does not present the unobservable 16384 boundary as measured.
AGENTS.md reference: [AGENTS.md:L20-L23](https://github.com/Lochnair/irtt-rs/blob/b3b754075b850acc6b26dfa36d9ad24ced0a588f/AGENTS.md#L20-L23)
Useful? React with 👍 / 👎.
Remove the unsupported per-session fill prescription
The observation establishes only that upstream's deterministic pattern phase continues across sessions and listeners; it does not show a disclosure or require per-session state. Unlike no-fill residual data, a shared stream of the public fixed pattern cannot reveal another peer's packet contents, and alternatives such as deriving fill from packet data need no mutable per-session state. Keep this as behavioral evidence or state the actual no-cross-peer-data invariant rather than turning the capture into an architecture prescription.
**<sub><sub></sub></sub> Remove the unsupported per-session fill prescription**
The observation establishes only that upstream's deterministic pattern phase continues across sessions and listeners; it does not show a disclosure or require per-session state. Unlike no-fill residual data, a shared stream of the public fixed pattern cannot reveal another peer's packet contents, and alternatives such as deriving fill from packet data need no mutable per-session state. Keep this as behavioral evidence or state the actual no-cross-peer-data invariant rather than turning the capture into an architecture prescription.
AGENTS.md reference: [AGENTS.md:L28-L30](https://github.com/Lochnair/irtt-rs/blob/b3b754075b850acc6b26dfa36d9ad24ced0a588f/AGENTS.md#L28-L30)
Useful? React with 👍 / 👎.
Measure duration from the first served echo everywhere
When an oversized or foreign-endpoint request arrives before the first accepted echo, this new rule starts the maximum-duration clock at the later served echo, but the companion client specification still states at IRTT_CLIENT_PROTOCOL_SPEC.md:1520-1523 that it starts at the session's first echo request. Since both documents are compatibility baselines, update the client specification with this refinement so implementers do not receive conflicting lifecycle rules.
**<sub><sub></sub></sub> Measure duration from the first served echo everywhere**
When an oversized or foreign-endpoint request arrives before the first accepted echo, this new rule starts the maximum-duration clock at the later served echo, but the companion client specification still states at `IRTT_CLIENT_PROTOCOL_SPEC.md:1520-1523` that it starts at the session's first echo request. Since both documents are compatibility baselines, update the client specification with this refinement so implementers do not receive conflicting lifecycle rules.
AGENTS.md reference: [AGENTS.md:L18-L23](https://github.com/Lochnair/irtt-rs/blob/b3b754075b850acc6b26dfa36d9ad24ced0a588f/AGENTS.md#L18-L23)
Useful? React with 👍 / 👎.
The admitted capture contains three echo rounds per session, not four: its 32 packets comprise eight open packets plus 24 packets for three request/reply rounds. The verification report and behavioral vectors likewise explicitly say three rounds and label them rounds 1–3, so claiming all four rounds overstates the recorded evidence.
**<sub><sub></sub></sub> Correct the DSCP trial to three rounds**
The admitted capture contains three echo rounds per session, not four: its 32 packets comprise eight open packets plus 24 packets for three request/reply rounds. The verification report and behavioral vectors likewise explicitly say three rounds and label them rounds 1–3, so claiming all four rounds overstates the recorded evidence.
AGENTS.md reference: [AGENTS.md:L26-L30](https://github.com/Lochnair/irtt-rs/blob/b3b754075b850acc6b26dfa36d9ad24ced0a588f/AGENTS.md#L26-L30)
Useful? React with 👍 / 👎.
The status section defines uppercase MUST NOT as an interoperability requirement and defines a robustness recommendation as non-required advice, but this recommendation uses MUST NOT and the following text calls it a requirement. Because the same section says conforming clients cannot observe this behavior, either introduce and label a distinct project safety requirement or avoid the RFC keyword and requirement wording; otherwise implementers cannot tell which declared statement level applies.
**<sub><sub></sub></sub> Classify the must-not-crash rule consistently**
The status section defines uppercase `MUST NOT` as an interoperability requirement and defines a robustness recommendation as non-required advice, but this recommendation uses `MUST NOT` and the following text calls it a requirement. Because the same section says conforming clients cannot observe this behavior, either introduce and label a distinct project safety requirement or avoid the RFC keyword and requirement wording; otherwise implementers cannot tell which declared statement level applies.
AGENTS.md reference: [AGENTS.md:L20-L23](https://github.com/Lochnair/irtt-rs/blob/b3b754075b850acc6b26dfa36d9ad24ced0a588f/AGENTS.md#L20-L23)
Useful? React with 👍 / 👎.
Restrict the timestamp-policy variations to fatal cases
Both “Any of the above” rows also include StampAt = none and explicit Clock = 0, but those inputs respectively serve normally and are rejected during negotiation; neither becomes fatal merely because the server permits no timestamps or only one timestamp. The verification report correctly scopes these policy variations to “Any fatal case,” so make these rows refer only to the four non-none, absent-Clock cases.
**<sub><sub></sub></sub> Restrict the timestamp-policy variations to fatal cases**
Both “Any of the above” rows also include `StampAt = none` and explicit `Clock = 0`, but those inputs respectively serve normally and are rejected during negotiation; neither becomes fatal merely because the server permits no timestamps or only one timestamp. The verification report correctly scopes these policy variations to “Any fatal case,” so make these rows refer only to the four non-none, absent-Clock cases.
AGENTS.md reference: [AGENTS.md:L26-L30](https://github.com/Lochnair/irtt-rs/blob/b3b754075b850acc6b26dfa36d9ad24ced0a588f/AGENTS.md#L26-L30)
Useful? React with 👍 / 👎.
Do not claim an ordering absent from the DSCP capture
In server-dscp-interleaved.pcapng, all four open request/reply exchanges are frames 1–8 and the first marked echo reply is frame 10, so none of these open replies was sent immediately after a marked reply. This also contradicts the preceding description that the sessions were opened back to back before the echo rounds; remove the ordering claim or provide the separate evidence that actually exercises it.
**<sub><sub></sub></sub> Do not claim an ordering absent from the DSCP capture**
In `server-dscp-interleaved.pcapng`, all four open request/reply exchanges are frames 1–8 and the first marked echo reply is frame 10, so none of these open replies was sent immediately after a marked reply. This also contradicts the preceding description that the sessions were opened back to back before the echo rounds; remove the ordering claim or provide the separate evidence that actually exercises it.
AGENTS.md reference: [AGENTS.md:L26-L30](https://github.com/Lochnair/irtt-rs/blob/b3b754075b850acc6b26dfa36d9ad24ced0a588f/AGENTS.md#L26-L30)
Useful? React with 👍 / 👎.
Agreed — carried the refinement into IRTT_CLIENT_PROTOCOL_SPEC.md §19.3 so both compatibility baselines state the origin as the first served echo, with a dated note that the earlier measurements are unaffected (their first request was served), and recorded the change in a new "Part IV Client Spec Change Applied" table. 🤖 Addressed by Claude Code
Agreed — carried the refinement into `IRTT_CLIENT_PROTOCOL_SPEC.md` §19.3 so both compatibility baselines state the origin as the first *served* echo, with a dated note that the earlier measurements are unaffected (their first request was served), and recorded the change in a new "Part IV Client Spec Change Applied" table.
_🤖 Addressed by [Claude Code](https://claude.com/claude-code)_
Fixed — the row now reads "The open is answered normally, with a valid token. The session it creates is not usable: the first echo request on it is fatal to upstream." 🤖 Addressed by Claude Code
Fixed — the row now reads "The **open** is answered normally, with a valid token. The session it creates is not usable: the first echo request on it is fatal to upstream."
_🤖 Addressed by [Claude Code](https://claude.com/claude-code)_
Correct, and it was inconsistent with my own vectors and Part IV, which both said three. Verified against the capture (32 packets = 8 open + 3 rounds × 8) and changed the spec to "three interleaved rounds ... in all three rounds". 🤖 Addressed by Claude Code
Correct, and it was inconsistent with my own vectors and Part IV, which both said three. Verified against the capture (32 packets = 8 open + 3 rounds × 8) and changed the spec to "three interleaved rounds ... in all three rounds".
_🤖 Addressed by [Claude Code](https://claude.com/claude-code)_
Agreed — the loopback row only shows lengths to 8000 emitted unclamped. Byte-exactness is now claimed for the 1500 and 1280 byte interfaces only, with an explicit note that the loopback cap is unreachable on this host because a reply beyond roughly 9300 bytes ends the server first. Same correction applied to Finding S-25. 🤖 Addressed by Claude Code
Agreed — the loopback row only shows lengths to 8000 emitted unclamped. Byte-exactness is now claimed for the 1500 and 1280 byte interfaces only, with an explicit note that the loopback cap is unreachable on this host because a reply beyond roughly 9300 bytes ends the server first. Same correction applied to Finding S-25.
_🤖 Addressed by [Claude Code](https://claude.com/claude-code)_
Confirmed — frames 1–8 are the four open exchanges and the first marked echo reply is frame 10, so this capture cannot show that ordering. The ordering is independently supported by the existing dscp-values.pcapng (frame 4 marked echo reply, frame 7 unmarked open reply on the same listener), so I kept the observation and re-attributed it there, with a note in §10.1 saying what the interleaved capture does not show. 🤖 Addressed by Claude Code
Confirmed — frames 1–8 are the four open exchanges and the first marked echo reply is frame 10, so this capture cannot show that ordering. The ordering is independently supported by the existing `dscp-values.pcapng` (frame 4 marked echo reply, frame 7 unmarked open reply on the same listener), so I kept the observation and re-attributed it there, with a note in §10.1 saying what the interleaved capture does not show.
_🤖 Addressed by [Claude Code](https://claude.com/claude-code)_
Fixed — the recommendation no longer uses RFC 2119 keywords, and now states explicitly that they are reserved here for interoperability requirements and that how strictly the implementing project binds itself belongs in that project's guidance. 🤖 Addressed by Claude Code
Fixed — the recommendation no longer uses RFC 2119 keywords, and now states explicitly that they are reserved here for interoperability requirements and that how strictly the implementing project binds itself belongs in that project's guidance.
_🤖 Addressed by [Claude Code](https://claude.com/claude-code)_
Agreed, and this was the weakest thing in the commit — a fixed public pattern cannot disclose another peer's data, so the analogy to no-fill was wrong. Removed the per-session prescription entirely (and its entry in §24.3), kept the observation, and said plainly that no fill-state arrangement is prescribed. Also narrowed the claim to continuity across the sessions tested and the tested IPv4/IPv6 listeners. 🤖 Addressed by Claude Code
Agreed, and this was the weakest thing in the commit — a fixed public pattern cannot disclose another peer's data, so the analogy to no-fill was wrong. Removed the per-session prescription entirely (and its entry in §24.3), kept the observation, and said plainly that no fill-state arrangement is prescribed. Also narrowed the claim to continuity across the sessions tested and the tested IPv4/IPv6 listeners.
_🤖 Addressed by [Claude Code](https://claude.com/claude-code)_
Fixed — both rows now read "Any of the four fatal rows above", with a following sentence spelling out that the StampAt 0 and explicit Clock = 0 rows are excluded and why. 🤖 Addressed by Claude Code
Fixed — both rows now read "Any of the four **fatal** rows above", with a following sentence spelling out that the `StampAt 0` and explicit `Clock = 0` rows are excluded and why.
_🤖 Addressed by [Claude Code](https://claude.com/claude-code)_
Agreed — the sentence overreached. Now scoped to the reply direction, with the request direction stated explicitly: Length = 0 and DSCP = 0 are accepted, and Clock = 0 is rejected precisely because it is present carrying that value. 🤖 Addressed by Claude Code
Agreed — the sentence overreached. Now scoped to the reply direction, with the request direction stated explicitly: `Length = 0` and `DSCP = 0` are accepted, and `Clock = 0` is rejected precisely because it is present carrying that value.
_🤖 Addressed by [Claude Code](https://claude.com/claude-code)_
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".
### 💡 Codex Review
Here are some automated review suggestions for this pull request.
**Reviewed commit:** `6635464d0a`
<details> <summary>ℹ️ About Codex in GitHub</summary>
<br/>
[Your team has set up Codex to review pull requests in this repo](https://chatgpt.com/codex/cloud/settings/general). 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".
</details>
Section 18.2 still states unconditionally that the first request after the deadline is answered, but this new case makes the first such request a foreign-endpoint echo and explicitly drops it while consuming the session's final opportunity to reply. The same subsection now gives truncated, oversized, and foreign-close examples too, so qualify the earlier rule as applying only to an otherwise serviceable echo; otherwise implementers are told both to answer and to drop these first post-deadline packets.
**<sub><sub></sub></sub> Qualify which post-expiry request is answered**
Section 18.2 still states unconditionally that the first request after the deadline is answered, but this new case makes the first such request a foreign-endpoint echo and explicitly drops it while consuming the session's final opportunity to reply. The same subsection now gives truncated, oversized, and foreign-close examples too, so qualify the earlier rule as applying only to an otherwise serviceable echo; otherwise implementers are told both to answer and to drop these first post-deadline packets.
AGENTS.md reference: [AGENTS.md:L20-L30](https://github.com/Lochnair/irtt-rs/blob/6635464d0a5039a9b125c799529c4a5272c3248b/AGENTS.md#L20-L30)
Useful? React with 👍 / 👎.
Exclude close-flagged echo replies from unmarked closes
For a session with nonzero DSCP that reaches the maximum-duration deadline, this new row says the server-initiated close is an ordinary echo reply carrying the session's mark, while the unchanged conclusion at the end of Section 20 and client-spec Section 10.8 say that “close packets are unmarked.” Clarify that the latter means client close requests or standalone close packets, not close-flagged echo replies, so implementers do not clear the negotiated marking merely because the Close flag is set.
**<sub><sub></sub></sub> Exclude close-flagged echo replies from unmarked closes**
For a session with nonzero DSCP that reaches the maximum-duration deadline, this new row says the server-initiated close is an ordinary echo reply carrying the session's mark, while the unchanged conclusion at the end of Section 20 and client-spec Section 10.8 say that “close packets are unmarked.” Clarify that the latter means client close requests or standalone close packets, not close-flagged echo replies, so implementers do not clear the negotiated marking merely because the Close flag is set.
AGENTS.md reference: [AGENTS.md:L18-L23](https://github.com/Lochnair/irtt-rs/blob/6635464d0a5039a9b125c799529c4a5272c3248b/AGENTS.md#L18-L23)
Useful? React with 👍 / 👎.
After the fresh revision explicitly states in Section 22.5 that this advice is not an interoperability requirement and that its strength belongs to the implementing project, calling it “the requirement above” restores the same contradictory classification; the behavioral vector also still calls it a “must-not-crash requirement.” Use “recommendation” consistently so implementers can distinguish the compatibility baseline from project policy.
**<sub><sub></sub></sub> Keep the crash guidance a recommendation**
After the fresh revision explicitly states in Section 22.5 that this advice is not an interoperability requirement and that its strength belongs to the implementing project, calling it “the requirement above” restores the same contradictory classification; the behavioral vector also still calls it a “must-not-crash requirement.” Use “recommendation” consistently so implementers can distinguish the compatibility baseline from project policy.
AGENTS.md reference: [AGENTS.md:L18-L30](https://github.com/Lochnair/irtt-rs/blob/6635464d0a5039a9b125c799529c4a5272c3248b/AGENTS.md#L18-L30)
Useful? React with 👍 / 👎.
The fresh Section 9.2 wording now correctly says the loopback trial only reached 8000 bytes and cannot establish a 16384-byte cap because the process terminates around 9300, but this remaining-unknown entry still says all three interfaces were capped exactly at their MTUs. That leaves the compatibility baseline internally contradictory and again overstates the admitted evidence; limit the exact-cap claim here to the Ethernet and tunnel interfaces.
**<sub><sub></sub></sub> Do not claim an unmeasured loopback MTU cap**
The fresh Section 9.2 wording now correctly says the loopback trial only reached 8000 bytes and cannot establish a 16384-byte cap because the process terminates around 9300, but this remaining-unknown entry still says all three interfaces were capped exactly at their MTUs. That leaves the compatibility baseline internally contradictory and again overstates the admitted evidence; limit the exact-cap claim here to the Ethernet and tunnel interfaces.
AGENTS.md reference: [AGENTS.md:L20-L30](https://github.com/Lochnair/irtt-rs/blob/6635464d0a5039a9b125c799529c4a5272c3248b/AGENTS.md#L20-L30)
Useful? React with 👍 / 👎.
The table establishes the deadline origin only for an oversized first request and a foreign-endpoint first request; the deadline-crossing rate-limit trial does not test whether a rate-limited first request starts the clock. Generalizing this to a request dropped “for any reason” therefore turns two observations into an unsupported rule for every other admission/authentication drop class. State only the measured cases, or leave the other drop reasons ambiguous.
**<sub><sub></sub></sub> Scope deadline origin to tested drop classes**
The table establishes the deadline origin only for an oversized first request and a foreign-endpoint first request; the deadline-crossing rate-limit trial does not test whether a rate-limited first request starts the clock. Generalizing this to a request dropped “for any reason” therefore turns two observations into an unsupported rule for every other admission/authentication drop class. State only the measured cases, or leave the other drop reasons ambiguous.
AGENTS.md reference: [AGENTS.md:L10-L14](https://github.com/Lochnair/irtt-rs/blob/6635464d0a5039a9b125c799529c4a5272c3248b/AGENTS.md#L10-L14)
Useful? React with 👍 / 👎.
Right — dropping the RFC keywords was undone two sentences later. Changed "consistent with the requirement above" to "the recommendation above", reworded the closing sentence, and changed the behavioral vector's "must-not-crash requirement" to "recommendation". 🤖 Addressed by Claude Code
Right — dropping the RFC keywords was undone two sentences later. Changed "consistent with the requirement above" to "the recommendation above", reworded the closing sentence, and changed the behavioral vector's "must-not-crash requirement" to "recommendation".
_🤖 Addressed by [Claude Code](https://claude.com/claude-code)_
Missed this one when fixing §9.2 — §23.5 now says the exact cap holds for the Ethernet and tunnel interfaces only, records the loopback trial as a lower bound (lengths to 8000 unclamped, boundary unreachable because ~9300 ends the process), and adds "a host whose maximum outbound datagram size exceeds its loopback MTU" to what would resolve it. 🤖 Addressed by Claude Code
Missed this one when fixing §9.2 — §23.5 now says the exact cap holds for the Ethernet and tunnel interfaces only, records the loopback trial as a lower bound (lengths to 8000 unclamped, boundary unreachable because ~9300 ends the process), and adds "a host whose maximum outbound datagram size exceeds its loopback MTU" to what would resolve it.
_🤖 Addressed by [Claude Code](https://claude.com/claude-code)_
Agreed — only oversized and foreign-endpoint were tested in the first-request position, and the rate-limit trial is about crossing an already-running deadline, not starting one. Scoped to those two classes in the vector, spec §15.2 and Finding S-23, with the other drop classes explicitly left untested. 🤖 Addressed by Claude Code
Agreed — only oversized and foreign-endpoint were tested in the first-request position, and the rate-limit trial is about crossing an already-running deadline, not starting one. Scoped to those two classes in the vector, spec §15.2 and Finding S-23, with the other drop classes explicitly left untested.
_🤖 Addressed by [Claude Code](https://claude.com/claude-code)_
Agreed — qualified the §18.2 rule to a request that would otherwise be served, with a short paragraph explaining that a packet which would be dropped anyway is still dropped yet can still spend the release, so the single reply is not guaranteed to the session's own client. Vectors §8 now points at §8.3 for the same reason. 🤖 Addressed by Claude Code
Agreed — qualified the §18.2 rule to a request that would otherwise be served, with a short paragraph explaining that a packet which would be dropped anyway is still dropped yet can still spend the release, so the single reply is not guaranteed to the session's own client. Vectors §8 now points at §8.3 for the same reason.
_🤖 Addressed by [Claude Code](https://claude.com/claude-code)_
Agreed — added a paragraph to §20 scoping "open and close packets are unmarked" to standalone datagrams (open request, open reply, client close request) and stating that a server-initiated close is an echo reply carrying the session's marking, which must not be cleared because the Close flag is set. Added a matching dated clarification to client spec §10.8. 🤖 Addressed by Claude Code
Agreed — added a paragraph to §20 scoping "open and close packets are unmarked" to standalone datagrams (open request, open reply, client close request) and stating that a server-initiated close is an echo reply carrying the session's marking, which must not be cleared because the Close flag is set. Added a matching dated clarification to client spec §10.8.
_🤖 Addressed by [Claude Code](https://claude.com/claude-code)_
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".
### 💡 Codex Review
Here are some automated review suggestions for this pull request.
**Reviewed commit:** `0ca8988671`
<details> <summary>ℹ️ About Codex in GitHub</summary>
<br/>
[Your team has set up Codex to review pull requests in this repo](https://chatgpt.com/codex/cloud/settings/general). 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".
</details>
When the configured minimum interval exceeds idle timeout / 4, Section 7.3 explicitly says a fully conforming client sends at the shorter negotiated interval and is rate-limited, so the rationale here that conforming clients never encounter this state is false. For example, if the token refill interval also exceeds the idle deadline, refreshing on each dropped probe preserves the session until a later probe can be served, while ignoring those probes expires it before refill; that difference is observable by the conforming client. The behavior therefore cannot remain an unrestricted MAY under the configuration model documented by this specification.
**<sub><sub></sub></sub> Classify rate-limit activity for capped intervals**
When the configured minimum interval exceeds `idle timeout / 4`, Section 7.3 explicitly says a fully conforming client sends at the shorter negotiated interval and is rate-limited, so the rationale here that conforming clients never encounter this state is false. For example, if the token refill interval also exceeds the idle deadline, refreshing on each dropped probe preserves the session until a later probe can be served, while ignoring those probes expires it before refill; that difference is observable by the conforming client. The behavior therefore cannot remain an unrestricted `MAY` under the configuration model documented by this specification.
AGENTS.md reference: [AGENTS.md:L20-L23](https://github.com/Lochnair/irtt-rs/blob/0ca8988671c0f6a470de79a86c55c87a0fc3b161/AGENTS.md#L20-L23)
Useful? React with 👍 / 👎.
When the negotiated length is smaller than the mandatory echo header, a conforming client does send a request larger than the negotiated length: this same section documents a session negotiating length 10 whose requests are necessarily 16 bytes at lines 775–778. Retaining this assertion can lead an implementer to size or validate request handling from the negotiated value and miss the minimum-header case; explain the over-MTU result without claiming that request length is always bounded by the negotiated length.
**<sub><sub></sub></sub> Remove the false request-length invariant**
When the negotiated length is smaller than the mandatory echo header, a conforming client does send a request larger than the negotiated length: this same section documents a session negotiating length 10 whose requests are necessarily 16 bytes at lines 775–778. Retaining this assertion can lead an implementer to size or validate request handling from the negotiated value and miss the minimum-header case; explain the over-MTU result without claiming that request length is always bounded by the negotiated length.
AGENTS.md reference: [AGENTS.md:L20-L23](https://github.com/Lochnair/irtt-rs/blob/0ca8988671c0f6a470de79a86c55c87a0fc3b161/AGENTS.md#L20-L23)
Useful? React with 👍 / 👎.
For a session negotiating a negative DSCP value, this table says the echo reply carries that value verbatim, but the newly documented platform results at lines 1895–1899 say -1 is emitted as TOS 255 on IPv4 and traffic class 0 on IPv6; values above 255 produce no echo reply at all. Scope the table’s echo and server-close rows to negotiated values in 0..=255 and point out the out-of-range exceptions so implementers do not treat the later platform behavior as contradictory.
**<sub><sub></sub></sub> Scope verbatim DSCP marking to in-range values**
For a session negotiating a negative DSCP value, this table says the echo reply carries that value verbatim, but the newly documented platform results at lines 1895–1899 say `-1` is emitted as TOS 255 on IPv4 and traffic class 0 on IPv6; values above 255 produce no echo reply at all. Scope the table’s echo and server-close rows to negotiated values in `0..=255` and point out the out-of-range exceptions so implementers do not treat the later platform behavior as contradictory.
AGENTS.md reference: [AGENTS.md:L20-L30](https://github.com/Lochnair/irtt-rs/blob/0ca8988671c0f6a470de79a86c55c87a0fc3b161/AGENTS.md#L20-L30)
Useful? React with 👍 / 👎.
Qualify the maximum-duration trigger as the next served echo
When the first echo after the maximum-duration deadline is rate-limited, this newly documented case says it is dropped and a later served echo carries Close, contradicting the unqualified rule at lines 1472–1474—and the companion client specification at lines 1527–1531—that the first echo arriving after the deadline is answered with Close. Qualify those lifecycle summaries as the first echo that would otherwise be served so implementers do not close on the dropped request.
**<sub><sub></sub></sub> Qualify the maximum-duration trigger as the next served echo**
When the first echo after the maximum-duration deadline is rate-limited, this newly documented case says it is dropped and a later served echo carries Close, contradicting the unqualified rule at lines 1472–1474—and the companion client specification at lines 1527–1531—that the first echo arriving after the deadline is answered with Close. Qualify those lifecycle summaries as the first echo that would otherwise be served so implementers do not close on the dropped request.
AGENTS.md reference: [AGENTS.md:L18-L23](https://github.com/Lochnair/irtt-rs/blob/0ca8988671c0f6a470de79a86c55c87a0fc3b161/AGENTS.md#L18-L23)
Useful? React with 👍 / 👎.
Addressed in 2ed0e257. The false claim that conforming clients cannot be rate-limited was removed: the documented restriction interaction means a conforming client can encounter rate limiting. The combined liveness consequence is explicitly a black-box inference from separately measured behaviors and was deliberately not promoted to an unsupported unconditional RFC 2119 requirement.
Addressed in 2ed0e257. The false claim that conforming clients cannot be rate-limited was removed: the documented restriction interaction means a conforming client can encounter rate limiting. The combined liveness consequence is explicitly a black-box inference from separately measured behaviors and was deliberately not promoted to an unsupported unconditional RFC 2119 requirement.
Addressed in 2ed0e257. The documents now consistently distinguish origin = first served ECHO from trigger = first otherwise-serviceable ECHO after the deadline. A deadline-crossing rate-limited ECHO is dropped without Close; the next served ECHO carries it.
Addressed in 2ed0e257. The documents now consistently distinguish origin = first served ECHO from trigger = first otherwise-serviceable ECHO after the deadline. A deadline-crossing rate-limited ECHO is dropped without Close; the next served ECHO carries it.
Addressed in 2ed0e257. Removed the false request-length invariant from the over-MTU observation and now state only the measured-safe consequence: Negotiated Length is not by itself a valid receive-buffer upper bound because mandatory protocol structure can require a larger datagram.
Addressed in 2ed0e257. Removed the false request-length invariant from the over-MTU observation and now state only the measured-safe consequence: Negotiated Length is not by itself a valid receive-buffer upper bound because mandatory protocol structure can require a larger datagram.
Addressed in 2ed0e257. The normal echo and server-initiated-close marking summaries now scope verbatim session marking to negotiated values in 0..=255 and direct negative or out-of-range values to the documented host-specific behavior.
Addressed in 2ed0e257. The normal echo and server-initiated-close marking summaries now scope verbatim session marking to negotiated values in 0..=255 and direct negative or out-of-range values to the documented host-specific behavior.
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".
### 💡 Codex Review
Here are some automated review suggestions for this pull request.
**Reviewed commit:** `2ed0e2570e`
<details> <summary>ℹ️ About Codex in GitHub</summary>
<br/>
[Your team has set up Codex to review pull requests in this repo](https://chatgpt.com/codex/cloud/settings/general). 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".
</details>
When a clean server chooses the explicitly permitted policy of rejecting a non-none StampAt whenever the decoded Clock is zero, omitted Clock and explicit Clock = 0 may both be rejected without affecting any conforming client, so it does not have to retain presence in its decoded representation. Requiring every server to distinguish the forms turns this adversarial upstream observation into an internal architecture prescription and conflicts with Section 22.5's statement that the clean policy is deliberately open; scope this requirement to implementations reproducing upstream's distinct outcomes.
**<sub><sub></sub></sub> Keep parameter presence an optional policy detail**
When a clean server chooses the explicitly permitted policy of rejecting a non-none StampAt whenever the decoded Clock is zero, omitted Clock and explicit `Clock = 0` may both be rejected without affecting any conforming client, so it does not have to retain presence in its decoded representation. Requiring every server to distinguish the forms turns this adversarial upstream observation into an internal architecture prescription and conflicts with Section 22.5's statement that the clean policy is deliberately open; scope this requirement to implementations reproducing upstream's distinct outcomes.
AGENTS.md reference: [AGENTS.md:L28-L30](https://github.com/Lochnair/irtt-rs/blob/2ed0e2570ea18b118e78d9f4f196d0051e4963e7/AGENTS.md#L28-L30)
Useful? React with 👍 / 👎.
Limit the rejected-open claim to observable behavior
A well-formed open succeeding after a malformed one proves only that the rejection does not poison the next externally visible parse; it cannot establish that the rejected request “leaves nothing behind” or that no partial state is retained, especially when the same document says the default server has no observable session cap. Hidden allocation, counters, or discarded parse state could all produce the same replies, so narrow this to the subsequent-open result and leave internal retention ambiguous.
**<sub><sub></sub></sub> Limit the rejected-open claim to observable behavior**
A well-formed open succeeding after a malformed one proves only that the rejection does not poison the next externally visible parse; it cannot establish that the rejected request “leaves nothing behind” or that no partial state is retained, especially when the same document says the default server has no observable session cap. Hidden allocation, counters, or discarded parse state could all produce the same replies, so narrow this to the subsequent-open result and leave internal retention ambiguous.
AGENTS.md reference: [AGENTS.md:L12-L14](https://github.com/Lochnair/irtt-rs/blob/2ed0e2570ea18b118e78d9f4f196d0051e4963e7/AGENTS.md#L12-L14)
Useful? React with 👍 / 👎.
When the configured minimum exceeds idle timeout / 4, these lines establish that the returned interval can be 2 seconds while the limiter still enforces 5 seconds, but Section 9.3 says the server “enforces the negotiated minimum send interval.” An implementer following that sentence would refill at the returned 2-second cadence rather than the observed 5-second cadence; rewrite the limiter description to distinguish the configured enforcement interval from the negotiated value.
**<sub><sub></sub></sub> Name the configured interval as the limiter input**
When the configured minimum exceeds `idle timeout / 4`, these lines establish that the returned interval can be 2 seconds while the limiter still enforces 5 seconds, but Section 9.3 says the server “enforces the negotiated minimum send interval.” An implementer following that sentence would refill at the returned 2-second cadence rather than the observed 5-second cadence; rewrite the limiter description to distinguish the configured enforcement interval from the negotiated value.
AGENTS.md reference: [AGENTS.md:L18-L23](https://github.com/Lochnair/irtt-rs/blob/2ed0e2570ea18b118e78d9f4f196d0051e4963e7/AGENTS.md#L18-L23)
Useful? React with 👍 / 👎.
The 1499/1500 acceptance knees establish only the effective length used by the maximum-length decision; they cannot show that the datagram reached that policy already truncated or that its true length was never compared, because an implementation that receives all 3000 bytes and caps the comparison at the interface MTU has the same wire behavior. State that processing-order conclusion as an inference or leave the truncation point ambiguous rather than presenting an unobservable internal path as a measured fact.
**<sub><sub></sub></sub> Label the pre-policy truncation as an inference**
The 1499/1500 acceptance knees establish only the effective length used by the maximum-length decision; they cannot show that the datagram reached that policy already truncated or that its true length was never compared, because an implementation that receives all 3000 bytes and caps the comparison at the interface MTU has the same wire behavior. State that processing-order conclusion as an inference or leave the truncation point ambiguous rather than presenting an unobservable internal path as a measured fact.
AGENTS.md reference: [AGENTS.md:L12-L14](https://github.com/Lochnair/irtt-rs/blob/2ed0e2570ea18b118e78d9f4f196d0051e4963e7/AGENTS.md#L12-L14)
Useful? React with 👍 / 👎.
Exempt rate-limit drops from the no-state-change rule
When idle expiry is enabled, this behavior means a rate-limited request changes the session's observable lifetime, but Section 5.4 still says every listed discard condition—including an echo with no rate allowance—causes “no change to the state of any live session.” Qualify that blanket statement so implementers do not overlook the rate-limit refresh exception.
**<sub><sub></sub></sub> Exempt rate-limit drops from the no-state-change rule**
When idle expiry is enabled, this behavior means a rate-limited request changes the session's observable lifetime, but Section 5.4 still says every listed discard condition—including an echo with no rate allowance—causes “no change to the state of any live session.” Qualify that blanket statement so implementers do not overlook the rate-limit refresh exception.
AGENTS.md reference: [AGENTS.md:L18-L23](https://github.com/Lochnair/irtt-rs/blob/2ed0e2570ea18b118e78d9f4f196d0051e4963e7/AGENTS.md#L18-L23)
Useful? React with 👍 / 👎.
When the deadline-crossing echo is rate-limited, this new rule drops it and defers Close until a later served echo, but Section 17's compact adversarial table still says unconditionally that an “Echo after the maximum-duration deadline” receives a close-flagged reply and removes the session. Fresh evidence is that the still-unqualified row remains at Section 17 line 1632; qualify it as otherwise serviceable or add the rate-limited exception there.
**<sub><sub></sub></sub> Qualify the compact maximum-duration row**
When the deadline-crossing echo is rate-limited, this new rule drops it and defers Close until a later served echo, but Section 17's compact adversarial table still says unconditionally that an “Echo after the maximum-duration deadline” receives a close-flagged reply and removes the session. Fresh evidence is that the still-unqualified row remains at Section 17 line 1632; qualify it as otherwise serviceable or add the rate-limited exception there.
AGENTS.md reference: [AGENTS.md:L18-L23](https://github.com/Lochnair/irtt-rs/blob/2ed0e2570ea18b118e78d9f4f196d0051e4963e7/AGENTS.md#L18-L23)
Useful? React with 👍 / 👎.
These newly documented cases show that a foreign-endpoint, truncated, or oversized echo can release an expired session without a reply, yet Section 17's compact table still says every “Echo after idle expiry deadline” is replied to once. Fresh evidence is the remaining unconditional row at Section 17 line 1633; carry the otherwise-serviceable qualification into that summary so the compatibility baseline does not prescribe the opposite outcomes.
**<sub><sub></sub></sub> Qualify the compact idle-expiry row**
These newly documented cases show that a foreign-endpoint, truncated, or oversized echo can release an expired session without a reply, yet Section 17's compact table still says every “Echo after idle expiry deadline” is replied to once. Fresh evidence is the remaining unconditional row at Section 17 line 1633; carry the otherwise-serviceable qualification into that summary so the compatibility baseline does not prescribe the opposite outcomes.
AGENTS.md reference: [AGENTS.md:L20-L30](https://github.com/Lochnair/irtt-rs/blob/2ed0e2570ea18b118e78d9f4f196d0051e4963e7/AGENTS.md#L20-L30)
Useful? React with 👍 / 👎.
Addressed in 389c26b. Section 5.4 now states only silent discard and no reply, says rate-limited requests extend the observed idle lifetime, and defers the detailed comparison to Section 9.3. It makes no hidden-state claim.
Addressed in 389c26b. Section 5.4 now states only silent discard and no reply, says rate-limited requests extend the observed idle lifetime, and defers the detailed comparison to Section 9.3. It makes no hidden-state claim.
Addressed in 389c26b. The compact row now requires an otherwise-serviceable ECHO, specifies the normal Close-flagged reply and counted request, and names the rate-limited trigger exception.
Addressed in 389c26b. The compact row now requires an otherwise-serviceable ECHO, specifies the normal Close-flagged reply and counted request, and names the rate-limited trigger exception.
Addressed in 389c26b. The compact row now applies only to an otherwise-serviceable ECHO that is the first tested packet to touch the expired session, and it points to Section 18.2 for normally dropped packets that can release it first.
Addressed in 389c26b. The compact row now applies only to an otherwise-serviceable ECHO that is the first tested packet to touch the expired session, and it points to Section 18.2 for normally dropped packets that can release it first.
Addressed in 389c26b. The wire and upstream distinction remains documented; the text now requires only implementations reproducing distinct upstream outcomes to retain enough request-validation information. It prescribes no decoded representation and permits clean policy to map adversarial forms to the same safe outcome.
Addressed in 389c26b. The wire and upstream distinction remains documented; the text now requires only implementations reproducing distinct upstream outcomes to retain enough request-validation information. It prescribes no decoded representation and permits clean policy to map adversarial forms to the same safe outcome.
Addressed in 389c26b. The measured 1499/1500 and 1279/1280 decision boundaries were retained; the claim that truncation occurred before policy was removed or labelled only as an inference because black-box evidence cannot establish that internal ordering.
Addressed in 389c26b. The measured 1499/1500 and 1279/1280 decision boundaries were retained; the claim that truncation occurred before policy was removed or labelled only as an inference because black-box evidence cannot establish that internal ordering.
Addressed in 389c26b. Section 9.3 now distinguishes the configured minimum interval used by the tested limiter from the negotiated interval returned to the client; token-bucket wording is explicitly a black-box inference.
Addressed in 389c26b. Section 9.3 now distinguishes the configured minimum interval used by the tested limiter from the negotiated interval returned to the client; token-bucket wording is explicitly a black-box inference.
Addressed in 389c26b. The finding now states only that a malformed OPEN does not prevent a subsequent well-formed OPEN from succeeding; hidden retained, accounting, and parser state are left unspecified.
Addressed in 389c26b. The finding now states only that a malformed OPEN does not prevent a subsequent well-formed OPEN from succeeding; hidden retained, accounting, and parser state are left unspecified.
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".
### 💡 Codex Review
Here are some automated review suggestions for this pull request.
**Reviewed commit:** `389c26bb6c`
<details> <summary>ℹ️ About Codex in GitHub</summary>
<br/>
[Your team has set up Codex to review pull requests in this repo](https://chatgpt.com/codex/cloud/settings/general). 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".
</details>
When the fill pattern length does not divide the payload length, resetting versus continuing the phase produces different reply bytes—the four 7-byte payloads immediately above demonstrate exactly that distinction—so a client or packet capture can observe which policy was chosen even though the payload has no protocol meaning. Fresh evidence after the earlier fill-state review is this newly added assertion that “nothing observable distinguishes” the alternatives; describe them as interoperability-equivalent instead of contradicting the measured phase observation.
**<sub><sub></sub></sub> Do not call fill-phase alternatives unobservable**
When the fill pattern length does not divide the payload length, resetting versus continuing the phase produces different reply bytes—the four 7-byte payloads immediately above demonstrate exactly that distinction—so a client or packet capture can observe which policy was chosen even though the payload has no protocol meaning. Fresh evidence after the earlier fill-state review is this newly added assertion that “nothing observable distinguishes” the alternatives; describe them as interoperability-equivalent instead of contradicting the measured phase observation.
AGENTS.md reference: [AGENTS.md:L12-L14](https://github.com/Lochnair/irtt-rs/blob/389c26bb6c89403dce2ff12fa01f43c2b0175240/AGENTS.md#L12-L14)
Useful? React with 👍 / 👎.
Limit dropped close triggers to the tested rate-limit case
When a maximum-duration deadline is crossed by an oversized, foreign-endpoint, truncated, or otherwise dropped request, these lines prescribe that the session remains live until the next served echo. The admitted Finding S-23 evidence exercises only a rate-limited request in the deadline-crossing position; the other two drop classes were tested only before the clock started, so their post-deadline behavior remains ambiguous. Fresh evidence after the earlier review is the new “such as” wording, which generalizes the rate-limit result to every independent drop reason; scope this statement to rate limiting rather than defining unmeasured lifecycle behavior.
**<sub><sub></sub></sub> Limit dropped close triggers to the tested rate-limit case**
When a maximum-duration deadline is crossed by an oversized, foreign-endpoint, truncated, or otherwise dropped request, these lines prescribe that the session remains live until the next served echo. The admitted Finding S-23 evidence exercises only a rate-limited request in the deadline-crossing position; the other two drop classes were tested only before the clock started, so their post-deadline behavior remains ambiguous. Fresh evidence after the earlier review is the new “such as” wording, which generalizes the rate-limit result to every independent drop reason; scope this statement to rate limiting rather than defining unmeasured lifecycle behavior.
AGENTS.md reference: [AGENTS.md:L12-L14](https://github.com/Lochnair/irtt-rs/blob/389c26bb6c89403dce2ff12fa01f43c2b0175240/AGENTS.md#L12-L14)
Useful? React with 👍 / 👎.
Corrected in 11e8a9bf3fcffa6dd9ceb5ed4cd7fcf5c6144ee8. Section 15.2 now says only the tested rate-limited deadline-crossing Echo was silently dropped without Close, the session remained usable, and the next served Echo carried Close. It explicitly leaves the corresponding behavior of other independently dropped post-deadline classes untested and unspecified. The client specification stale generalization was narrowed to match.
Corrected in 11e8a9bf3fcffa6dd9ceb5ed4cd7fcf5c6144ee8. Section 15.2 now says only the tested rate-limited deadline-crossing Echo was silently dropped without Close, the session remained usable, and the next served Echo carried Close. It explicitly leaves the corresponding behavior of other independently dropped post-deadline classes untested and unspecified. The client specification stale generalization was narrowed to match.
Corrected in 11e8a9bf3fcffa6dd9ceb5ed4cd7fcf5c6144ee8. Section 13.3 now states that reset and continuation can produce different payload bytes, making phase policy observable in a packet capture, but are interoperability-equivalent because a conforming client cannot depend on payload phase. The verification report now says the same, and no fill-state arrangement or per-session-state prescription was added.
Corrected in 11e8a9bf3fcffa6dd9ceb5ed4cd7fcf5c6144ee8. Section 13.3 now states that reset and continuation can produce different payload bytes, making phase policy observable in a packet capture, but are interoperability-equivalent because a conforming client cannot depend on payload phase. The verification report now says the same, and no fill-state arrangement or per-session-state prescription was added.
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".
### 💡 Codex Review
Here are some automated review suggestions for this pull request.
**Reviewed commit:** `11e8a9bf3f`
<details> <summary>ℹ️ About Codex in GitHub</summary>
<br/>
[Your team has set up Codex to review pull requests in this repo](https://chatgpt.com/codex/cloud/settings/general). 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".
</details>
Do not classify post-idle behavior as unobservable
When the client-to-server path is interrupted for longer than idle timeout + 5 s but recovers before a longer negotiated test duration ends, a conforming client does enter this state: Section 18.2 says upstream answers its first otherwise-serviceable echo after recovery, whereas an implementation using either permitted alternative here remains silent. Those are observably different outcomes, so the claim that no conforming client can tell and that every outcome is silence cannot justify making the behavior unrestricted; account for mid-test packet loss or narrow the classification accordingly.
**<sub><sub></sub></sub> Do not classify post-idle behavior as unobservable**
When the client-to-server path is interrupted for longer than `idle timeout + 5 s` but recovers before a longer negotiated test duration ends, a conforming client does enter this state: Section 18.2 says upstream answers its first otherwise-serviceable echo after recovery, whereas an implementation using either permitted alternative here remains silent. Those are observably different outcomes, so the claim that no conforming client can tell and that every outcome is silence cannot justify making the behavior unrestricted; account for mid-test packet loss or narrow the classification accordingly.
AGENTS.md reference: [AGENTS.md:L20-L30](https://github.com/Lochnair/irtt-rs/blob/11e8a9bf3fcffa6dd9ceb5ed4cd7fcf5c6144ee8/AGENTS.md#L20-L30)
Useful? React with 👍 / 👎.
Label the idle boundary as a session-release boundary
For the 2-second case, the preceding observed-behavior table says a request at 7.1 seconds is still answered and only the immediately following request is dropped, so the 7.00-second entry cannot literally be the shortest gap whose request is “not served.” The boundary sweep evidently uses the follow-up probe to determine that the session was released; label this column as the shortest gap after which the follow-up is dropped, or record both probe outcomes, so readers do not implement immediate expiry at the listed boundary.
**<sub><sub></sub></sub> Label the idle boundary as a session-release boundary**
For the 2-second case, the preceding observed-behavior table says a request at 7.1 seconds is still answered and only the immediately following request is dropped, so the 7.00-second entry cannot literally be the shortest gap whose request is “not served.” The boundary sweep evidently uses the follow-up probe to determine that the session was released; label this column as the shortest gap after which the follow-up is dropped, or record both probe outcomes, so readers do not implement immediate expiry at the listed boundary.
AGENTS.md reference: [AGENTS.md:L20-L30](https://github.com/Lochnair/irtt-rs/blob/11e8a9bf3fcffa6dd9ceb5ed4cd7fcf5c6144ee8/AGENTS.md#L20-L30)
Useful? React with 👍 / 👎.
Qualify endpoint-mismatch invariants for expired sessions
When a foreign-endpoint packet arrives after the idle deadline, this new behavior says it releases the session, but Sections 8.1 and 15.1 still state without qualification that a foreign echo leaves the session intact and a foreign close does not remove it; the conformance summary likewise requires endpoint mismatches to be dropped without disturbing the session. Explicitly scope those older rules to live, non-expired sessions or cross-reference this expiry exception so implementers are not given opposite lifecycle requirements.
**<sub><sub></sub></sub> Qualify endpoint-mismatch invariants for expired sessions**
When a foreign-endpoint packet arrives after the idle deadline, this new behavior says it releases the session, but Sections 8.1 and 15.1 still state without qualification that a foreign echo leaves the session intact and a foreign close does not remove it; the conformance summary likewise requires endpoint mismatches to be dropped without disturbing the session. Explicitly scope those older rules to live, non-expired sessions or cross-reference this expiry exception so implementers are not given opposite lifecycle requirements.
AGENTS.md reference: [AGENTS.md:L20-L30](https://github.com/Lochnair/irtt-rs/blob/11e8a9bf3fcffa6dd9ceb5ed4cd7fcf5c6144ee8/AGENTS.md#L20-L30)
Useful? React with 👍 / 👎.
Addressed in cbd75fd6bfb3a3cdb1cad5d5fd8f9c0f99d3aed1. The false “no conforming client can tell” claim was removed; a conforming client can observe the difference after sufficiently long mid-test client-to-server path loss and recovery. This was not promoted to a new unsupported RFC 2119 MUST; the clean implementation policy remains open.
Addressed in cbd75fd6bfb3a3cdb1cad5d5fd8f9c0f99d3aed1. The false “no conforming client can tell” claim was removed; a conforming client can observe the difference after sufficiently long mid-test client-to-server path loss and recovery. This was not promoted to a new unsupported RFC 2119 MUST; the clean implementation policy remains open.
Addressed in cbd75fd6bfb3a3cdb1cad5d5fd8f9c0f99d3aed1. Live-session endpoint-mismatch behavior remains unchanged, while the text now scopes out and cross-references the separately observed expired-session release exception in Sections 8.1, 15.1, and 17; Finding S-1 now carries the same live-session scope.
Addressed in cbd75fd6bfb3a3cdb1cad5d5fd8f9c0f99d3aed1. Live-session endpoint-mismatch behavior remains unchanged, while the text now scopes out and cross-references the separately observed expired-session release exception in Sections 8.1, 15.1, and 17; Finding S-1 now carries the same live-session scope.
Addressed in cbd75fd6bfb3a3cdb1cad5d5fd8f9c0f99d3aed1. The timeout+5 values now describe the observed session-release boundary detected by the immediate follow-up probe, not a threshold at which the first post-gap request itself stops receiving a reply. The verification report and behavioral vectors use the same follow-up-based labels.
Addressed in cbd75fd6bfb3a3cdb1cad5d5fd8f9c0f99d3aed1. The timeout+5 values now describe the observed session-release boundary detected by the immediate follow-up probe, not a threshold at which the first post-gap request itself stops receiving a reply. The verification report and behavioral vectors use the same follow-up-based labels.
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".
### 💡 Codex Review
Here are some automated review suggestions for this pull request.
**Reviewed commit:** `cbd75fd6bf`
<details> <summary>ℹ️ About Codex in GitHub</summary>
<br/>
[Your team has set up Codex to review pull requests in this repo](https://chatgpt.com/codex/cloud/settings/general). 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".
</details>
Exempt no-timestamp servers from the fatal Clock row
When the server is configured to provide no timestamps, Section 22.5 and the behavioral vector say it restricts the requested non-none StampAt to none and serves this absent-Clock session normally. This unconditional admission-table row instead says every such request creates an unusable session whose first echo is fatal; qualify it for the default/single-timestamp policies or include the no-timestamp exception so the compatibility baseline does not prescribe opposite outcomes.
**<sub><sub></sub></sub> Exempt no-timestamp servers from the fatal Clock row**
When the server is configured to provide no timestamps, Section 22.5 and the behavioral vector say it restricts the requested non-none `StampAt` to none and serves this absent-Clock session normally. This unconditional admission-table row instead says every such request creates an unusable session whose first echo is fatal; qualify it for the default/single-timestamp policies or include the no-timestamp exception so the compatibility baseline does not prescribe opposite outcomes.
AGENTS.md reference: [AGENTS.md:L20-L30](https://github.com/Lochnair/irtt-rs/blob/cbd75fd6bfb3a3cdb1cad5d5fd8f9c0f99d3aed1/AGENTS.md#L20-L30)
Useful? React with 👍 / 👎.
Distinguish triggering the crash from observing it
When a nonconforming peer triggers this defect while well-behaved clients have sessions on the same process, the preceding lines state that every session stops being served, so those clients can observe whether the server survived. This does not make reproducing the crash an interoperability requirement, but the rationale should say that a conforming client cannot trigger the state rather than claiming the resulting outage is unobservable.
**<sub><sub></sub></sub> Distinguish triggering the crash from observing it**
When a nonconforming peer triggers this defect while well-behaved clients have sessions on the same process, the preceding lines state that every session stops being served, so those clients can observe whether the server survived. This does not make reproducing the crash an interoperability requirement, but the rationale should say that a conforming client cannot *trigger* the state rather than claiming the resulting outage is unobservable.
AGENTS.md reference: [AGENTS.md:L18-L23](https://github.com/Lochnair/irtt-rs/blob/cbd75fd6bfb3a3cdb1cad5d5fd8f9c0f99d3aed1/AGENTS.md#L18-L23)
Useful? React with 👍 / 👎.
Addressed in 47bf6a2f0f563ca91365a13c4b97a67f01246fb9. The fatal absent-Clock result is now scoped to cases where restriction leaves the restricted (effective) StampAt non-none; the tested no-timestamp policy restricts StampAt to none and serves the session normally.
Addressed in 47bf6a2f0f563ca91365a13c4b97a67f01246fb9. The fatal absent-Clock result is now scoped to cases where restriction leaves the restricted (effective) StampAt non-none; the tested no-timestamp policy restricts StampAt to none and serves the session normally.
Addressed in 47bf6a2f0f563ca91365a13c4b97a67f01246fb9. Conforming clients cannot themselves trigger the malformed negotiation, but unrelated conforming clients can observe the resulting process-wide outage if another peer triggers it. Reproducing the crash remains a robustness defect, not an interoperability requirement.
Addressed in 47bf6a2f0f563ca91365a13c4b97a67f01246fb9. Conforming clients cannot themselves trigger the malformed negotiation, but unrelated conforming clients can observe the resulting process-wide outage if another peer triggers it. Reproducing the crash remains a robustness defect, not an interoperability requirement.
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".
### 💡 Codex Review
Here are some automated review suggestions for this pull request.
**Reviewed commit:** `47bf6a2f0f`
<details> <summary>ℹ️ About Codex in GitHub</summary>
<br/>
[Your team has set up Codex to review pull requests in this repo](https://chatgpt.com/codex/cloud/settings/general). 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".
</details>
Do not narrow fatal configurations to two listener types
The experiments only establish this failure for the tested loopback/wildcard setup, so saying the reachable configurations are “exactly” loopback or wildcard overgeneralizes the evidence. A directly bound jumbo-MTU interface could also have a reply cap above the host's outbound datagram ceiling, and Section 23.5 explicitly leaves jumbo interfaces and other platforms untested; scope this to the observed configurations or state the actual condition that the reply cap exceeds the transmit ceiling.
**<sub><sub></sub></sub> Do not narrow fatal configurations to two listener types**
The experiments only establish this failure for the tested loopback/wildcard setup, so saying the reachable configurations are “exactly” loopback or wildcard overgeneralizes the evidence. A directly bound jumbo-MTU interface could also have a reply cap above the host's outbound datagram ceiling, and Section 23.5 explicitly leaves jumbo interfaces and other platforms untested; scope this to the observed configurations or state the actual condition that the reply cap exceeds the transmit ceiling.
AGENTS.md reference: [AGENTS.md:L12-L14](https://github.com/Lochnair/irtt-rs/blob/47bf6a2f0f563ca91365a13c4b97a67f01246fb9/AGENTS.md#L12-L14)
Useful? React with 👍 / 👎.
This definition says black-box inferences never describe an internal mechanism, but the document immediately uses that marker for a token-bucket mechanism in Section 9.3 and for lookup/creation-driven expiry rather than scheduled removal in Section 18.2. Those are appropriately qualified hypotheses, but they still describe mechanisms, so the statement-level definition contradicts its own uses; define the level as not asserting a mechanism as fact, or remove the mechanism descriptions.
**<sub><sub></sub></sub> Make the inference definition match its uses**
This definition says black-box inferences never describe an internal mechanism, but the document immediately uses that marker for a token-bucket mechanism in Section 9.3 and for lookup/creation-driven expiry rather than scheduled removal in Section 18.2. Those are appropriately qualified hypotheses, but they still describe mechanisms, so the statement-level definition contradicts its own uses; define the level as not *asserting* a mechanism as fact, or remove the mechanism descriptions.
AGENTS.md reference: [AGENTS.md:L12-L14](https://github.com/Lochnair/irtt-rs/blob/47bf6a2f0f563ca91365a13c4b97a67f01246fb9/AGENTS.md#L12-L14)
Useful? React with 👍 / 👎.
Remove the blanket unobservable-recommendation claim
The fresh text correctly acknowledges that a process-wide failure caused by another peer is observable to a conforming client, but the statement-level table in Section 1 still defines every robustness recommendation as something “no existing client can observe whether it was followed.” The new send-failure and accepted-parameter recommendations directly invalidate that blanket definition, so update the table to say these are non-interoperability requirements without claiming their effects are universally unobservable.
**<sub><sub></sub></sub> Remove the blanket unobservable-recommendation claim**
The fresh text correctly acknowledges that a process-wide failure caused by another peer is observable to a conforming client, but the statement-level table in Section 1 still defines every robustness recommendation as something “no existing client can observe whether it was followed.” The new send-failure and accepted-parameter recommendations directly invalidate that blanket definition, so update the table to say these are non-interoperability requirements without claiming their effects are universally unobservable.
AGENTS.md reference: [AGENTS.md:L20-L23](https://github.com/Lochnair/irtt-rs/blob/47bf6a2f0f563ca91365a13c4b97a67f01246fb9/AGENTS.md#L20-L23)
Useful? React with 👍 / 👎.
Addressed in 064b7d550107c7e4d10cd96c93796c8d2731e07b. The definition now permits explicitly labelled explanatory mechanism hypotheses, but does not treat those mechanisms as directly observed fact and keeps them non-load-bearing. Section 18.2 now also describes its expiry explanation as not directly measured.
Addressed in 064b7d550107c7e4d10cd96c93796c8d2731e07b. The definition now permits explicitly labelled explanatory mechanism hypotheses, but does not treat those mechanisms as directly observed fact and keeps them non-load-bearing. Section 18.2 now also describes its expiry explanation as not directly measured.
Addressed in 064b7d550107c7e4d10cd96c93796c8d2731e07b. “Exactly loopback or wildcard” was removed. The text now scopes the observed failure to the tested configurations and the effective reply-cap versus host transmit-ceiling condition; jumbo and other untested interfaces remain unresolved.
Addressed in 064b7d550107c7e4d10cd96c93796c8d2731e07b. “Exactly loopback or wildcard” was removed. The text now scopes the observed failure to the tested configurations and the effective reply-cap versus host transmit-ceiling condition; jumbo and other untested interfaces remain unresolved.
Addressed in 064b7d550107c7e4d10cd96c93796c8d2731e07b. The definition now says these are non-interoperability resilience/safety recommendations; their consequences may still be visible to conforming clients, consistent with Section 24.3.
Addressed in 064b7d550107c7e4d10cd96c93796c8d2731e07b. The definition now says these are non-interoperability resilience/safety recommendations; their consequences may still be visible to conforming clients, consistent with Section 24.3.
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".
### 💡 Codex Review
Here are some automated review suggestions for this pull request.
**Reviewed commit:** `064b7d5501`
<details> <summary>ℹ️ About Codex in GitHub</summary>
<br/>
[Your team has set up Codex to review pull requests in this repo](https://chatgpt.com/codex/cloud/settings/general). 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".
</details>
Scope invalid duplicate handling to the orders actually tested
The vectors at SERVER_BEHAVIORAL_VECTORS.md lines 427–435 exercise an invalid occurrence in both positions only for Duration; Clock and ServerFill are tested only with the invalid value second, and the other known tags have no invalid-duplicate rows. Therefore the parser-wide claim that any invalid occurrence rejects regardless of position exceeds the admitted evidence and could misdirect an implementation whose validation differs by parameter type. Scope the position-independent rule to Duration and the explicitly tested rows, or label the broader conclusion as an inference/remaining ambiguity.
**<sub><sub></sub></sub> Scope invalid duplicate handling to the orders actually tested**
The vectors at `SERVER_BEHAVIORAL_VECTORS.md` lines 427–435 exercise an invalid occurrence in both positions only for Duration; Clock and ServerFill are tested only with the invalid value second, and the other known tags have no invalid-duplicate rows. Therefore the parser-wide claim that any invalid occurrence rejects regardless of position exceeds the admitted evidence and could misdirect an implementation whose validation differs by parameter type. Scope the position-independent rule to Duration and the explicitly tested rows, or label the broader conclusion as an inference/remaining ambiguity.
AGENTS.md reference: [AGENTS.md:L12-L14](https://github.com/Lochnair/irtt-rs/blob/064b7d550107c7e4d10cd96c93796c8d2731e07b/AGENTS.md#L12-L14)
Useful? React with 👍 / 👎.
Distinguish DSCP application failures from send failures
For an out-of-range DSCP value, these lines call the missing replies send failures while also establishing that the server continues serving its other sessions. Section 6.3, however, says a non-transient reply send failure terminates the listener and whole process. Black-box evidence supports only that these replies were absent and unrelated sessions stayed healthy; it cannot identify whether applying the marking failed before transmission or the send itself failed. State the observable outcome and leave the failure stage ambiguous, or explicitly distinguish this error class from the fatal send failures.
**<sub><sub></sub></sub> Distinguish DSCP application failures from send failures**
For an out-of-range DSCP value, these lines call the missing replies send failures while also establishing that the server continues serving its other sessions. Section 6.3, however, says a non-transient reply send failure terminates the listener and whole process. Black-box evidence supports only that these replies were absent and unrelated sessions stayed healthy; it cannot identify whether applying the marking failed before transmission or the send itself failed. State the observable outcome and leave the failure stage ambiguous, or explicitly distinguish this error class from the fatal send failures.
AGENTS.md reference: [AGENTS.md:L12-L14](https://github.com/Lochnair/irtt-rs/blob/064b7d550107c7e4d10cd96c93796c8d2731e07b/AGENTS.md#L12-L14)
Useful? React with 👍 / 👎.
Qualify the conformance summary for expired sessions
When a foreign-endpoint packet is the first to touch an idle-expired session, these lines establish that it releases the session, but Section 24.1 item 7 still requires endpoint-check failures to be dropped “without disturbing the session.” Fresh evidence after the earlier review thread is that this unconditional summary remains at lines 2367–2368 in the final tree. Scope that requirement to live, non-expired sessions or cross-reference this expiry exception so implementers are not given contradictory lifecycle rules.
**<sub><sub></sub></sub> Qualify the conformance summary for expired sessions**
When a foreign-endpoint packet is the first to touch an idle-expired session, these lines establish that it releases the session, but Section 24.1 item 7 still requires endpoint-check failures to be dropped “without disturbing the session.” Fresh evidence after the earlier review thread is that this unconditional summary remains at lines 2367–2368 in the final tree. Scope that requirement to live, non-expired sessions or cross-reference this expiry exception so implementers are not given contradictory lifecycle rules.
AGENTS.md reference: [AGENTS.md:L20-L30](https://github.com/Lochnair/irtt-rs/blob/064b7d550107c7e4d10cd96c93796c8d2731e07b/AGENTS.md#L20-L30)
Useful? React with 👍 / 👎.
Addressed in 221c38e166983b8c6ba691e163030986ad0ce1d6. Valid last-value-wins evidence remains broad across the nine tested known tags. Invalid-duplicate behavior is now scoped to Duration in both tested orders and the tested invalid-second Clock and ServerFill rows; untested orders and parameters are explicitly unspecified in the spec, vectors, verification report, and PR body.
Addressed in 221c38e166983b8c6ba691e163030986ad0ce1d6. Valid last-value-wins evidence remains broad across the nine tested known tags. Invalid-duplicate behavior is now scoped to Duration in both tested orders and the tested invalid-second Clock and ServerFill rows; untested orders and parameters are explicitly unspecified in the spec, vectors, verification report, and PR body.
Addressed in 221c38e166983b8c6ba691e163030986ad0ce1d6. The final conformance checklist now scopes “session remains usable” to live, non-expired sessions and cross-references the separately observed expired-session release behavior in Section 18.2.
Addressed in 221c38e166983b8c6ba691e163030986ad0ce1d6. The final conformance checklist now scopes “session remains usable” to live, non-expired sessions and cross-references the separately observed expired-session release behavior in Section 18.2.
Addressed in 221c38e166983b8c6ba691e163030986ad0ce1d6. The docs now record only the observable result for DSCP >=256: OPEN succeeds, the affected session emits no observed ECHO reply, and unrelated sessions remain healthy. The exact failure stage is explicitly left unknown and is no longer called a verified send failure; it is distinguished from the fatal outbound send failure.
Addressed in 221c38e166983b8c6ba691e163030986ad0ce1d6. The docs now record only the observable result for DSCP >=256: OPEN succeeds, the affected session emits no observed ECHO reply, and unrelated sessions remain healthy. The exact failure stage is explicitly left unknown and is no longer called a verified send failure; it is distinguished from the fatal outbound send failure.
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".
### 💡 Codex Review
Here are some automated review suggestions for this pull request.
**Reviewed commit:** `221c38e166`
<details> <summary>ℹ️ About Codex in GitHub</summary>
<br/>
[Your team has set up Codex to review pull requests in this repo](https://chatgpt.com/codex/cloud/settings/general). 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".
</details>
Fresh evidence beyond the earlier specification fix is that this S-25 subheading remains unqualified: it says replies are capped at the bound interface's MTU, while the loopback result immediately below explicitly did not reach or observe its 16384-byte cap, and other platforms remain untested. Scope this heading to the measured Ethernet and tunnel interfaces, or describe only the observed effective boundary, so the evidence report does not present an unresolved host-specific rule as fact.
**<sub><sub></sub></sub> Limit the MTU-cap claim to measured interfaces**
Fresh evidence beyond the earlier specification fix is that this S-25 subheading remains unqualified: it says replies are capped at the bound interface's MTU, while the loopback result immediately below explicitly did not reach or observe its 16384-byte cap, and other platforms remain untested. Scope this heading to the measured Ethernet and tunnel interfaces, or describe only the observed effective boundary, so the evidence report does not present an unresolved host-specific rule as fact.
AGENTS.md reference: [AGENTS.md:L12-L14](https://github.com/Lochnair/irtt-rs/blob/221c38e166983b8c6ba691e163030986ad0ce1d6/AGENTS.md#L12-L14)
Useful? React with 👍 / 👎.
The body limits this comparison to the enumerated classes (Every class tested), and the companion specification and vectors consistently call rate limiting the only tested drop class with this effect. Dropping that qualifier in the finding title turns the admitted comparison into a universal claim about all discard paths; retain “tested” here so unmeasured cases remain explicitly ambiguous.
**<sub><sub></sub></sub> Qualify the drop-class heading as tested**
The body limits this comparison to the enumerated classes (`Every class tested`), and the companion specification and vectors consistently call rate limiting the only **tested** drop class with this effect. Dropping that qualifier in the finding title turns the admitted comparison into a universal claim about all discard paths; retain “tested” here so unmeasured cases remain explicitly ambiguous.
AGENTS.md reference: [AGENTS.md:L12-L14](https://github.com/Lochnair/irtt-rs/blob/221c38e166983b8c6ba691e163030986ad0ce1d6/AGENTS.md#L12-L14)
Useful? React with 👍 / 👎.
Agreed — the heading outran its own body. Now reads "On the two interfaces where the cap was reachable, the emitted reply is capped at the bind interface's MTU", leaving the loopback row as the lower bound it is (lengths to 8000 unclamped; ~9300 ends the process before 16384 can be observed). 🤖 Addressed by Claude Code
Agreed — the heading outran its own body. Now reads "On the two interfaces where the cap was reachable, the emitted reply is capped at the bind interface's MTU", leaving the loopback row as the lower bound it is (lengths to 8000 unclamped; ~9300 ends the process before 16384 can be observed).
_🤖 Addressed by [Claude Code](https://claude.com/claude-code)_
Agreed — the title was the only place missing the qualifier the body, the spec and the vectors all carry. Finding S-20 is now "the only tested drop class that keeps a session alive". 🤖 Addressed by Claude Code
Agreed — the title was the only place missing the qualifier the body, the spec and the vectors all carry. Finding S-20 is now "the only **tested** drop class that keeps a session alive".
_🤖 Addressed by [Claude Code](https://claude.com/claude-code)_
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".
### 💡 Codex Review
Here are some automated review suggestions for this pull request.
**Reviewed commit:** `3f02372f5b`
<details> <summary>ℹ️ About Codex in GitHub</summary>
<br/>
[Your team has set up Codex to review pull requests in this repo](https://chatgpt.com/codex/cloud/settings/general). 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".
</details>
The sweeps cover only idle timeouts of 500 ms, 2 s, and 4 s and maximum durations of 500 ms, 1 s, and 3 s, so they establish constant margins across those tested settings—not across the entire configurable value domain. Calling both margins constant across “the configured value” promotes a three-point observation into an unrestricted rule; qualify the conclusion to the measured values or label the broader extrapolation as an inference/remaining ambiguity.
**<sub><sub></sub></sub> Limit constant margins to the measured settings**
The sweeps cover only idle timeouts of 500 ms, 2 s, and 4 s and maximum durations of 500 ms, 1 s, and 3 s, so they establish constant margins across those tested settings—not across the entire configurable value domain. Calling both margins constant across “the configured value” promotes a three-point observation into an unrestricted rule; qualify the conclusion to the measured values or label the broader extrapolation as an inference/remaining ambiguity.
AGENTS.md reference: [AGENTS.md:L12-L14](https://github.com/Lochnair/irtt-rs/blob/3f02372f5bb3b55c726ecda7863f04c344838157/AGENTS.md#L12-L14)
Useful? React with 👍 / 👎.
The admitted experiment only shows that a burst of ordinary opens caused the expired session to disappear before the subsequent probe; it does not establish that one ordinary open always reclaims an expired session rather than reclamation depending on a threshold or another batch condition. This row turns that batch outcome into a per-request invariant, so describe only the tested burst or leave single-open behavior ambiguous.
**<sub><sub></sub></sub> Scope reclamation to the tested open burst**
The admitted experiment only shows that a burst of ordinary opens caused the expired session to disappear before the subsequent probe; it does not establish that one ordinary open always reclaims an expired session rather than reclamation depending on a threshold or another batch condition. This row turns that batch outcome into a per-request invariant, so describe only the tested burst or leave single-open behavior ambiguous.
AGENTS.md reference: [AGENTS.md:L12-L14](https://github.com/Lochnair/irtt-rs/blob/3f02372f5bb3b55c726ecda7863f04c344838157/AGENTS.md#L12-L14)
Useful? React with 👍 / 👎.
The admitted negative-marking evidence identifies only DSCP = -1 producing IPv4 TOS 255 (the older -5 row records delivery but not the emitted TOS). That single mapping cannot distinguish modulo-256 conversion from clamping, special-case handling, or another platform behavior, so describing it as “the value taken modulo 256” asserts an unmeasured transformation. State only -1 → 255 or label modulo conversion as an inference.
**<sub><sub></sub></sub> Report only the observed negative DSCP mapping**
The admitted negative-marking evidence identifies only `DSCP = -1` producing IPv4 TOS 255 (the older `-5` row records delivery but not the emitted TOS). That single mapping cannot distinguish modulo-256 conversion from clamping, special-case handling, or another platform behavior, so describing it as “the value taken modulo 256” asserts an unmeasured transformation. State only `-1 → 255` or label modulo conversion as an inference.
AGENTS.md reference: [AGENTS.md:L12-L14](https://github.com/Lochnair/irtt-rs/blob/3f02372f5bb3b55c726ecda7863f04c344838157/AGENTS.md#L12-L14)
Useful? React with 👍 / 👎.
Agreed — only the burst was tested. §18.2 now reads "A burst of ordinary opens released an expired session; a burst of no-test opens did not", and states that whether a single open suffices, or whether a count/rate matters, was not measured. The §16 row now compares burst with burst rather than implying a per-open invariant. 🤖 Addressed by Claude Code
Agreed — only the burst was tested. §18.2 now reads "A burst of ordinary opens released an expired session; a burst of no-test opens did not", and states that whether a single open suffices, or whether a count/rate matters, was not measured. The §16 row now compares burst with burst rather than implying a per-open invariant.
_🤖 Addressed by [Claude Code](https://claude.com/claude-code)_
Agreed — three swept points each. Finding S-22 now names the settings, says the sweeps rule out a margin proportional to the configured value over the range tested (which is what "additive" means here), and records that a threshold or different behavior outside that range would not have shown up and stays untested. 🤖 Addressed by Claude Code
Agreed — three swept points each. Finding S-22 now names the settings, says the sweeps rule out a margin proportional to the configured value over the range tested (which is what "additive" means here), and records that a threshold or different behavior outside that range would not have shown up and stays untested.
_🤖 Addressed by [Claude Code](https://claude.com/claude-code)_
Agreed — modulo-256, clamping to the byte range and a −1 special case all predict TOS 255 for the one negative value whose marking was recorded. The spec and the vector now state the −1 → 255 mapping and say the transformation is not identified; Part IV already avoided the modulo claim. 🤖 Addressed by Claude Code
Agreed — modulo-256, clamping to the byte range and a −1 special case all predict TOS 255 for the one negative value whose marking was recorded. The spec and the vector now state the −1 → 255 mapping and say the transformation is not identified; Part IV already avoided the modulo claim.
_🤖 Addressed by [Claude Code](https://claude.com/claude-code)_
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".
### 💡 Codex Review
Here are some automated review suggestions for this pull request.
**Reviewed commit:** `7f5d252520`
<details> <summary>ℹ️ About Codex in GitHub</summary>
<br/>
[Your team has set up Codex to review pull requests in this repo](https://chatgpt.com/codex/cloud/settings/general). 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".
</details>
Remove the unobservable expiry-boundary count claim
In this trial the foreign-endpoint packet receives no reply and the session is already unavailable when every later probe arrives, so no emitted statistic reveals whether that packet changed the received count before release. The earlier live-session endpoint test does not establish counter handling on this distinct expired-session path; retain the observed drop and release outcome, but leave whether it was internally counted ambiguous.
**<sub><sub></sub></sub> Remove the unobservable expiry-boundary count claim**
In this trial the foreign-endpoint packet receives no reply and the session is already unavailable when every later probe arrives, so no emitted statistic reveals whether that packet changed the received count before release. The earlier live-session endpoint test does not establish counter handling on this distinct expired-session path; retain the observed drop and release outcome, but leave whether it was internally counted ambiguous.
AGENTS.md reference: [AGENTS.md:L12-L14](https://github.com/Lochnair/irtt-rs/blob/7f5d2525201b8c3ff35ea4cbc7526639a6e43401/AGENTS.md#L12-L14)
Useful? React with 👍 / 👎.
Remove clamping from the indistinguishable mappings
Clamping -1 to the byte range 0..=255 produces 0, not 255, so the observed IPv4 mapping actually distinguishes ordinary clamping from modulo-256 conversion. Keeping clamping in this list makes the stated ambiguity mathematically incorrect; remove it or define the different conversion that was intended.
**<sub><sub></sub></sub> Remove clamping from the indistinguishable mappings**
Clamping `-1` to the byte range `0..=255` produces `0`, not `255`, so the observed IPv4 mapping actually distinguishes ordinary clamping from modulo-256 conversion. Keeping clamping in this list makes the stated ambiguity mathematically incorrect; remove it or define the different conversion that was intended.
AGENTS.md reference: [AGENTS.md:L12-L14](https://github.com/Lochnair/irtt-rs/blob/7f5d2525201b8c3ff35ea4cbc7526639a6e43401/AGENTS.md#L12-L14)
Useful? React with 👍 / 👎.
You are right and my arithmetic was wrong — clamping −1 into 0..=255 gives 0, so the observation excludes clamping rather than leaving it ambiguous. The candidates are now the low byte of the two's-complement representation (equivalently the value modulo 256) and a special case for this input, and the text records that plain clamping is ruled out because it would have emitted 0. 🤖 Addressed by Claude Code
You are right and my arithmetic was wrong — clamping −1 into `0..=255` gives 0, so the observation excludes clamping rather than leaving it ambiguous. The candidates are now the low byte of the two's-complement representation (equivalently the value modulo 256) and a special case for this input, and the text records that plain clamping is ruled out because it would have emitted 0.
_🤖 Addressed by [Claude Code](https://claude.com/claude-code)_
Agreed — the session emitted no further reply, so no statistic can report whether that packet advanced the count. Finding S-1's not-counted result was measured on a live session where a later reply exposed the count, and I was carrying it onto a path where it does not apply. The report and the vector now state the release outcome and leave the counting question open; spec §18.2 already avoided the claim. 🤖 Addressed by Claude Code
Agreed — the session emitted no further reply, so no statistic can report whether that packet advanced the count. Finding S-1's not-counted result was measured on a live session where a later reply exposed the count, and I was carrying it onto a path where it does not apply. The report and the vector now state the release outcome and leave the counting question open; spec §18.2 already avoided the claim.
_🤖 Addressed by [Claude Code](https://claude.com/claude-code)_
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".
### 💡 Codex Review
Here are some automated review suggestions for this pull request.
**Reviewed commit:** `629ead0832`
<details> <summary>ℹ️ About Codex in GitHub</summary>
<br/>
[Your team has set up Codex to review pull requests in this repo](https://chatgpt.com/codex/cloud/settings/general). 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".
</details>
When a server-initiated Close is sent for a session with nonzero DSCP, the recorded evidence does not establish that it retains the mark: server-dscp-interleaved.pcapng contains only ordinary echo replies, while server-close.pcapng uses TOS 0 throughout. Calling the Close reply an ordinary marked echo assumes that setting the flag cannot affect marking; either document an observed nonzero-DSCP Close exchange or leave this behavior ambiguous rather than making it normative elsewhere.
**<sub><sub></sub></sub> Mark close-reply DSCP behavior as unverified**
When a server-initiated Close is sent for a session with nonzero DSCP, the recorded evidence does not establish that it retains the mark: `server-dscp-interleaved.pcapng` contains only ordinary echo replies, while `server-close.pcapng` uses TOS 0 throughout. Calling the Close reply an ordinary marked echo assumes that setting the flag cannot affect marking; either document an observed nonzero-DSCP Close exchange or leave this behavior ambiguous rather than making it normative elsewhere.
AGENTS.md reference: [AGENTS.md:L12-L14](https://github.com/Lochnair/irtt-rs/blob/629ead0832e2d7b9c48a7f33f6523bd5672db08e/AGENTS.md#L12-L14)
Useful? React with 👍 / 👎.
Qualify the blanket visibility claim in Section 22
When another peer triggers this defect, these lines explicitly say unrelated conforming clients observe the process-wide outage, contradicting Section 22's premise at lines 2106–2109 that no conforming client can tell which robustness choice was made. Fresh evidence after the prior review is that this blanket sentence remains in the final tree alongside the newly documented counterexample; qualify it to the triggering exchange or internal cause rather than all externally visible consequences.
**<sub><sub></sub></sub> Qualify the blanket visibility claim in Section 22**
When another peer triggers this defect, these lines explicitly say unrelated conforming clients observe the process-wide outage, contradicting Section 22's premise at lines 2106–2109 that no conforming client can tell which robustness choice was made. Fresh evidence after the prior review is that this blanket sentence remains in the final tree alongside the newly documented counterexample; qualify it to the triggering exchange or internal cause rather than all externally visible consequences.
AGENTS.md reference: [AGENTS.md:L20-L23](https://github.com/Lochnair/irtt-rs/blob/629ead0832e2d7b9c48a7f33f6523bd5672db08e/AGENTS.md#L20-L23)
Useful? React with 👍 / 👎.
Confirmed by checking every admitted capture — none contains a Close-flagged reply with nonzero TOS, and server-close.pcapng is TOS 0 throughout because that session negotiated no DSCP. The marking is a measured result, so I kept it but dropped the "ordinary marked echo reply that also sets the Close flag" clause (it argued from the flag rather than reporting the observation) and both tables now state that no capture shows it. Nothing normative depended on it: §15.2 and §24 make no marking claim. 🤖 Addressed by Claude Code
Confirmed by checking every admitted capture — none contains a Close-flagged reply with nonzero TOS, and `server-close.pcapng` is TOS 0 throughout because that session negotiated no DSCP. The marking is a measured result, so I kept it but dropped the "ordinary marked echo reply that also sets the Close flag" clause (it argued from the flag rather than reporting the observation) and both tables now state that no capture shows it. Nothing normative depended on it: §15.2 and §24 make no marking claim.
_🤖 Addressed by [Claude Code](https://claude.com/claude-code)_
Agreed — §22's preamble contradicted its own §22.1 and §22.5. It now rests the classification on what a conforming client can provoke: it cannot reach these outcomes and nothing about the wire is required, but the consequences are plainly visible to clients sharing the process. (The §1 statement-level table was fixed for the same defect earlier; this was the remaining site.) 🤖 Addressed by Claude Code
Agreed — §22's preamble contradicted its own §22.1 and §22.5. It now rests the classification on what a conforming client can *provoke*: it cannot reach these outcomes and nothing about the wire is required, but the consequences are plainly visible to clients sharing the process. (The §1 statement-level table was fixed for the same defect earlier; this was the remaining site.)
_🤖 Addressed by [Claude Code](https://claude.com/claude-code)_
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Transfer independently black-box-verified server behavior from a source-assisted research phase conducted outside this repository. Only a sanitizer-candidate report of black-box findings and the packet captures it referenced were admitted; no upstream source, tests, history, harnesses, build trees, result files or source-assisted analysis crossed the boundary.
New upstream robustness defect: when an OPEN requests timestamps, omits the Clock parameter, and server restriction leaves StampAt non-none, upstream accepts the OPEN with a valid token and no Clock echoed, then the first ECHO terminates the server process. A tested no-timestamp server policy instead restricts StampAt to none and serves the session normally. An explicit
Clock=0is instead rejected at OPEN, so parameter presence is externally meaningful. This is recorded as an observed defect with a clean-server robustness recommendation; the implementation policy is deliberately left open.Strengthened from thin or single-point evidence:
New parser and negotiation edges include repeated known tags being last-valid-wins; invalid duplicate evidence is limited to Duration in both orders and invalid-second Clock/ServerFill forms, with other orders and parameters unspecified; unknown tag values being accepted in the tested varint form, negative Length negotiation behavior, and the distinction between omitted and explicitly-zero parameter values.
The review pass also reconciles the client and server specifications around maximum-duration timing, tightens evidence attribution for DSCP and MTU observations, and removes unsupported implementation prescriptions from the fill findings.
Host- and environment-specific figures are labelled as such throughout. Upstream defects and quirks are not promoted to interoperability requirements, black-box inferences are explicitly marked, and no production implementation policy is chosen here.
Documentation and sanitized packet evidence only; no production code changed.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:
b3b754075bℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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".
For an open with non-none
StampAtand noClock, this row says the session is answered normally while immediately stating that its first echo is fatal. The report and behavioral vector establish that only the open request is answered normally; the resulting session is unusable. Reword this to say the open is answered normally so the admission table does not contradict the documented defect.AGENTS.md reference: AGENTS.md:L20-L23
Useful? React with 👍 / 👎.
Present-zero forms do exist in the request direction: this same section discusses an explicit
Clock = 0, the admission table acceptsLength = 0andDSCP = 0, and the new clock-absent capture includes an explicit zero Length tag. Only restricted zero values in open replies are omitted, so narrow this sentence to the reply direction rather than telling decoders that no request can encode a present zero.AGENTS.md reference: AGENTS.md:L20-L23
Useful? React with 👍 / 👎.
The loopback result cannot establish a cap at its exact 16384-byte MTU: the table only exercises lengths through 8000, while Section 22.1 says the host begins terminating the server around 9300, well before a reply can reach the loopback MTU. The evidence therefore demonstrates an exact cap for the 1500- and 1280-byte interfaces and only a lower bound on loopback; revise the three-interface claim so the verified baseline does not present the unobservable 16384 boundary as measured.
AGENTS.md reference: AGENTS.md:L20-L23
Useful? React with 👍 / 👎.
The observation establishes only that upstream's deterministic pattern phase continues across sessions and listeners; it does not show a disclosure or require per-session state. Unlike no-fill residual data, a shared stream of the public fixed pattern cannot reveal another peer's packet contents, and alternatives such as deriving fill from packet data need no mutable per-session state. Keep this as behavioral evidence or state the actual no-cross-peer-data invariant rather than turning the capture into an architecture prescription.
AGENTS.md reference: AGENTS.md:L28-L30
Useful? React with 👍 / 👎.
@@ -1476,7 +1831,8 @@ them resident indefinitely as upstream does.Requests dropped for rate limiting still refresh the idle clock, so a clientWhen an oversized or foreign-endpoint request arrives before the first accepted echo, this new rule starts the maximum-duration clock at the later served echo, but the companion client specification still states at
IRTT_CLIENT_PROTOCOL_SPEC.md:1520-1523that it starts at the session's first echo request. Since both documents are compatibility baselines, update the client specification with this refinement so implementers do not receive conflicting lifecycle rules.AGENTS.md reference: AGENTS.md:L18-L23
Useful? React with 👍 / 👎.
@@ -1478,2 +1833,3 @@sending faster than the allowance keeps its session alive without receivingreplies.replies. Section 9.3 records the full drop-class comparison establishing this,and that no other tested drop class has the same effect.The admitted capture contains three echo rounds per session, not four: its 32 packets comprise eight open packets plus 24 packets for three request/reply rounds. The verification report and behavioral vectors likewise explicitly say three rounds and label them rounds 1–3, so claiming all four rounds overstates the recorded evidence.
AGENTS.md reference: AGENTS.md:L26-L30
Useful? React with 👍 / 👎.
The status section defines uppercase
MUST NOTas an interoperability requirement and defines a robustness recommendation as non-required advice, but this recommendation usesMUST NOTand the following text calls it a requirement. Because the same section says conforming clients cannot observe this behavior, either introduce and label a distinct project safety requirement or avoid the RFC keyword and requirement wording; otherwise implementers cannot tell which declared statement level applies.AGENTS.md reference: AGENTS.md:L20-L23
Useful? React with 👍 / 👎.
Both “Any of the above” rows also include
StampAt = noneand explicitClock = 0, but those inputs respectively serve normally and are rejected during negotiation; neither becomes fatal merely because the server permits no timestamps or only one timestamp. The verification report correctly scopes these policy variations to “Any fatal case,” so make these rows refer only to the four non-none, absent-Clock cases.AGENTS.md reference: AGENTS.md:L26-L30
Useful? React with 👍 / 👎.
In
server-dscp-interleaved.pcapng, all four open request/reply exchanges are frames 1–8 and the first marked echo reply is frame 10, so none of these open replies was sent immediately after a marked reply. This also contradicts the preceding description that the sessions were opened back to back before the echo rounds; remove the ordering claim or provide the separate evidence that actually exercises it.AGENTS.md reference: AGENTS.md:L26-L30
Useful? React with 👍 / 👎.
@@ -1476,7 +1831,8 @@ them resident indefinitely as upstream does.Requests dropped for rate limiting still refresh the idle clock, so a clientAgreed — carried the refinement into
IRTT_CLIENT_PROTOCOL_SPEC.md§19.3 so both compatibility baselines state the origin as the first served echo, with a dated note that the earlier measurements are unaffected (their first request was served), and recorded the change in a new "Part IV Client Spec Change Applied" table.🤖 Addressed by Claude Code
Fixed — the row now reads "The open is answered normally, with a valid token. The session it creates is not usable: the first echo request on it is fatal to upstream."
🤖 Addressed by Claude Code
@@ -1478,2 +1833,3 @@sending faster than the allowance keeps its session alive without receivingreplies.replies. Section 9.3 records the full drop-class comparison establishing this,and that no other tested drop class has the same effect.Correct, and it was inconsistent with my own vectors and Part IV, which both said three. Verified against the capture (32 packets = 8 open + 3 rounds × 8) and changed the spec to "three interleaved rounds ... in all three rounds".
🤖 Addressed by Claude Code
Agreed — the loopback row only shows lengths to 8000 emitted unclamped. Byte-exactness is now claimed for the 1500 and 1280 byte interfaces only, with an explicit note that the loopback cap is unreachable on this host because a reply beyond roughly 9300 bytes ends the server first. Same correction applied to Finding S-25.
🤖 Addressed by Claude Code
Confirmed — frames 1–8 are the four open exchanges and the first marked echo reply is frame 10, so this capture cannot show that ordering. The ordering is independently supported by the existing
dscp-values.pcapng(frame 4 marked echo reply, frame 7 unmarked open reply on the same listener), so I kept the observation and re-attributed it there, with a note in §10.1 saying what the interleaved capture does not show.🤖 Addressed by Claude Code
Fixed — the recommendation no longer uses RFC 2119 keywords, and now states explicitly that they are reserved here for interoperability requirements and that how strictly the implementing project binds itself belongs in that project's guidance.
🤖 Addressed by Claude Code
Agreed, and this was the weakest thing in the commit — a fixed public pattern cannot disclose another peer's data, so the analogy to no-fill was wrong. Removed the per-session prescription entirely (and its entry in §24.3), kept the observation, and said plainly that no fill-state arrangement is prescribed. Also narrowed the claim to continuity across the sessions tested and the tested IPv4/IPv6 listeners.
🤖 Addressed by Claude Code
Fixed — both rows now read "Any of the four fatal rows above", with a following sentence spelling out that the
StampAt 0and explicitClock = 0rows are excluded and why.🤖 Addressed by Claude Code
Agreed — the sentence overreached. Now scoped to the reply direction, with the request direction stated explicitly:
Length = 0andDSCP = 0are accepted, andClock = 0is rejected precisely because it is present carrying that value.🤖 Addressed by Claude Code
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:
6635464d0aℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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".
Section 18.2 still states unconditionally that the first request after the deadline is answered, but this new case makes the first such request a foreign-endpoint echo and explicitly drops it while consuming the session's final opportunity to reply. The same subsection now gives truncated, oversized, and foreign-close examples too, so qualify the earlier rule as applying only to an otherwise serviceable echo; otherwise implementers are told both to answer and to drop these first post-deadline packets.
AGENTS.md reference: AGENTS.md:L20-L30
Useful? React with 👍 / 👎.
For a session with nonzero DSCP that reaches the maximum-duration deadline, this new row says the server-initiated close is an ordinary echo reply carrying the session's mark, while the unchanged conclusion at the end of Section 20 and client-spec Section 10.8 say that “close packets are unmarked.” Clarify that the latter means client close requests or standalone close packets, not close-flagged echo replies, so implementers do not clear the negotiated marking merely because the Close flag is set.
AGENTS.md reference: AGENTS.md:L18-L23
Useful? React with 👍 / 👎.
After the fresh revision explicitly states in Section 22.5 that this advice is not an interoperability requirement and that its strength belongs to the implementing project, calling it “the requirement above” restores the same contradictory classification; the behavioral vector also still calls it a “must-not-crash requirement.” Use “recommendation” consistently so implementers can distinguish the compatibility baseline from project policy.
AGENTS.md reference: AGENTS.md:L18-L30
Useful? React with 👍 / 👎.
@@ -1732,0 +2206,4 @@token and the restricted parameters;- the reply carries **no** Clock parameter, and no Clock value is synthesizedinto it;- the **first echo request** on that session receives **no reply**, and theThe fresh Section 9.2 wording now correctly says the loopback trial only reached 8000 bytes and cannot establish a 16384-byte cap because the process terminates around 9300, but this remaining-unknown entry still says all three interfaces were capped exactly at their MTUs. That leaves the compatibility baseline internally contradictory and again overstates the admitted evidence; limit the exact-cap claim here to the Ethernet and tunnel interfaces.
AGENTS.md reference: AGENTS.md:L20-L30
Useful? React with 👍 / 👎.
@@ -264,6 +266,38 @@ session:The table establishes the deadline origin only for an oversized first request and a foreign-endpoint first request; the deadline-crossing rate-limit trial does not test whether a rate-limited first request starts the clock. Generalizing this to a request dropped “for any reason” therefore turns two observations into an unsupported rule for every other admission/authentication drop class. State only the measured cases, or leave the other drop reasons ambiguous.
AGENTS.md reference: AGENTS.md:L10-L14
Useful? React with 👍 / 👎.
Right — dropping the RFC keywords was undone two sentences later. Changed "consistent with the requirement above" to "the recommendation above", reworded the closing sentence, and changed the behavioral vector's "must-not-crash requirement" to "recommendation".
🤖 Addressed by Claude Code
@@ -1732,0 +2206,4 @@token and the restricted parameters;- the reply carries **no** Clock parameter, and no Clock value is synthesizedinto it;- the **first echo request** on that session receives **no reply**, and theMissed this one when fixing §9.2 — §23.5 now says the exact cap holds for the Ethernet and tunnel interfaces only, records the loopback trial as a lower bound (lengths to 8000 unclamped, boundary unreachable because ~9300 ends the process), and adds "a host whose maximum outbound datagram size exceeds its loopback MTU" to what would resolve it.
🤖 Addressed by Claude Code
@@ -264,6 +266,38 @@ session:Agreed — only oversized and foreign-endpoint were tested in the first-request position, and the rate-limit trial is about crossing an already-running deadline, not starting one. Scoped to those two classes in the vector, spec §15.2 and Finding S-23, with the other drop classes explicitly left untested.
🤖 Addressed by Claude Code
Agreed — qualified the §18.2 rule to a request that would otherwise be served, with a short paragraph explaining that a packet which would be dropped anyway is still dropped yet can still spend the release, so the single reply is not guaranteed to the session's own client. Vectors §8 now points at §8.3 for the same reason.
🤖 Addressed by Claude Code
Agreed — added a paragraph to §20 scoping "open and close packets are unmarked" to standalone datagrams (open request, open reply, client close request) and stating that a server-initiated close is an echo reply carrying the session's marking, which must not be cleared because the Close flag is set. Added a matching dated clarification to client spec §10.8.
🤖 Addressed by Claude Code
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:
0ca8988671ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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".
@@ -609,0 +720,4 @@The loopback row establishes something weaker, and is not evidence of an exact16384-byte cap. All it shows is that lengths up to 8000 were emitted unclamped.The cap could not be approached there: on this host a reply beyond roughly 9300When the configured minimum interval exceeds
idle timeout / 4, Section 7.3 explicitly says a fully conforming client sends at the shorter negotiated interval and is rate-limited, so the rationale here that conforming clients never encounter this state is false. For example, if the token refill interval also exceeds the idle deadline, refreshing on each dropped probe preserves the session until a later probe can be served, while ignoring those probes expires it before refill; that difference is observable by the conforming client. The behavior therefore cannot remain an unrestrictedMAYunder the configuration model documented by this specification.AGENTS.md reference: AGENTS.md:L20-L23
Useful? React with 👍 / 👎.
@@ -627,0 +774,4 @@| **Request with no rate allowance left** | **no** | **YES** |The rate-limit row was established three ways against each other, and reproducedon the 0.9.0 release, the 0.9.1 release and the tested post-0.9.1 developmentWhen the negotiated length is smaller than the mandatory echo header, a conforming client does send a request larger than the negotiated length: this same section documents a session negotiating length 10 whose requests are necessarily 16 bytes at lines 775–778. Retaining this assertion can lead an implementer to size or validate request handling from the negotiated value and miss the minimum-header case; explain the over-MTU result without claiming that request length is always bounded by the negotiated length.
AGENTS.md reference: AGENTS.md:L20-L23
Useful? React with 👍 / 👎.
For a session negotiating a negative DSCP value, this table says the echo reply carries that value verbatim, but the newly documented platform results at lines 1895–1899 say
-1is emitted as TOS 255 on IPv4 and traffic class 0 on IPv6; values above 255 produce no echo reply at all. Scope the table’s echo and server-close rows to negotiated values in0..=255and point out the out-of-range exceptions so implementers do not treat the later platform behavior as contradictory.AGENTS.md reference: AGENTS.md:L20-L30
Useful? React with 👍 / 👎.
When the first echo after the maximum-duration deadline is rate-limited, this newly documented case says it is dropped and a later served echo carries Close, contradicting the unqualified rule at lines 1472–1474—and the companion client specification at lines 1527–1531—that the first echo arriving after the deadline is answered with Close. Qualify those lifecycle summaries as the first echo that would otherwise be served so implementers do not close on the dropped request.
AGENTS.md reference: AGENTS.md:L18-L23
Useful? React with 👍 / 👎.
@@ -609,0 +720,4 @@The loopback row establishes something weaker, and is not evidence of an exact16384-byte cap. All it shows is that lengths up to 8000 were emitted unclamped.The cap could not be approached there: on this host a reply beyond roughly 9300Addressed in 2ed0e257. The false claim that conforming clients cannot be rate-limited was removed: the documented restriction interaction means a conforming client can encounter rate limiting. The combined liveness consequence is explicitly a black-box inference from separately measured behaviors and was deliberately not promoted to an unsupported unconditional RFC 2119 requirement.
Addressed in 2ed0e257. The documents now consistently distinguish origin = first served ECHO from trigger = first otherwise-serviceable ECHO after the deadline. A deadline-crossing rate-limited ECHO is dropped without Close; the next served ECHO carries it.
@@ -627,0 +774,4 @@| **Request with no rate allowance left** | **no** | **YES** |The rate-limit row was established three ways against each other, and reproducedon the 0.9.0 release, the 0.9.1 release and the tested post-0.9.1 developmentAddressed in 2ed0e257. Removed the false request-length invariant from the over-MTU observation and now state only the measured-safe consequence: Negotiated Length is not by itself a valid receive-buffer upper bound because mandatory protocol structure can require a larger datagram.
Addressed in 2ed0e257. The normal echo and server-initiated-close marking summaries now scope verbatim session marking to negotiated values in 0..=255 and direct negative or out-of-range values to the documented host-specific behavior.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:
2ed0e2570eℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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".
When a clean server chooses the explicitly permitted policy of rejecting a non-none StampAt whenever the decoded Clock is zero, omitted Clock and explicit
Clock = 0may both be rejected without affecting any conforming client, so it does not have to retain presence in its decoded representation. Requiring every server to distinguish the forms turns this adversarial upstream observation into an internal architecture prescription and conflicts with Section 22.5's statement that the clean policy is deliberately open; scope this requirement to implementations reproducing upstream's distinct outcomes.AGENTS.md reference: AGENTS.md:L28-L30
Useful? React with 👍 / 👎.
A well-formed open succeeding after a malformed one proves only that the rejection does not poison the next externally visible parse; it cannot establish that the rejected request “leaves nothing behind” or that no partial state is retained, especially when the same document says the default server has no observable session cap. Hidden allocation, counters, or discarded parse state could all produce the same replies, so narrow this to the subsequent-open result and leave internal retention ambiguous.
AGENTS.md reference: AGENTS.md:L12-L14
Useful? React with 👍 / 👎.
@@ -609,0 +720,4 @@The loopback row establishes something weaker, and is not evidence of an exact16384-byte cap. All it shows is that lengths up to 8000 were emitted unclamped.The cap could not be approached there: on this host a reply beyond roughly 9300When the configured minimum exceeds
idle timeout / 4, these lines establish that the returned interval can be 2 seconds while the limiter still enforces 5 seconds, but Section 9.3 says the server “enforces the negotiated minimum send interval.” An implementer following that sentence would refill at the returned 2-second cadence rather than the observed 5-second cadence; rewrite the limiter description to distinguish the configured enforcement interval from the negotiated value.AGENTS.md reference: AGENTS.md:L18-L23
Useful? React with 👍 / 👎.
@@ -627,0 +789,4 @@the configured minimum interval used by the tested limiter: when the configuredminimum exceeds (idle timeout ÷ 4), the negotiated interval is the smaller valuewhile reply allowance still replenishes on the larger configured interval. Aclient that sends at the interval it was given can therefore itself beThe 1499/1500 acceptance knees establish only the effective length used by the maximum-length decision; they cannot show that the datagram reached that policy already truncated or that its true length was never compared, because an implementation that receives all 3000 bytes and caps the comparison at the interface MTU has the same wire behavior. State that processing-order conclusion as an inference or leave the truncation point ambiguous rather than presenting an unobservable internal path as a measured fact.
AGENTS.md reference: AGENTS.md:L12-L14
Useful? React with 👍 / 👎.
When idle expiry is enabled, this behavior means a rate-limited request changes the session's observable lifetime, but Section 5.4 still says every listed discard condition—including an echo with no rate allowance—causes “no change to the state of any live session.” Qualify that blanket statement so implementers do not overlook the rate-limit refresh exception.
AGENTS.md reference: AGENTS.md:L18-L23
Useful? React with 👍 / 👎.
@@ -1566,3 +1921,4 @@wire, not 46. Verified by capture; see `BLACKBOX_VERIFICATION_REPORT.md` Finding B and`captures/dscp-session.pcapng`.> **Out of scope: user-facing DSCP notation.** Whether an implementation'sWhen the deadline-crossing echo is rate-limited, this new rule drops it and defers Close until a later served echo, but Section 17's compact adversarial table still says unconditionally that an “Echo after the maximum-duration deadline” receives a close-flagged reply and removes the session. Fresh evidence is that the still-unqualified row remains at Section 17 line 1632; qualify it as otherwise serviceable or add the rate-limited exception there.
AGENTS.md reference: AGENTS.md:L18-L23
Useful? React with 👍 / 👎.
These newly documented cases show that a foreign-endpoint, truncated, or oversized echo can release an expired session without a reply, yet Section 17's compact table still says every “Echo after idle expiry deadline” is replied to once. Fresh evidence is the remaining unconditional row at Section 17 line 1633; carry the otherwise-serviceable qualification into that summary so the compatibility baseline does not prescribe the opposite outcomes.
AGENTS.md reference: AGENTS.md:L20-L30
Useful? React with 👍 / 👎.
Addressed in 389c26b. Section 5.4 now states only silent discard and no reply, says rate-limited requests extend the observed idle lifetime, and defers the detailed comparison to Section 9.3. It makes no hidden-state claim.
@@ -1566,3 +1921,4 @@wire, not 46. Verified by capture; see `BLACKBOX_VERIFICATION_REPORT.md` Finding B and`captures/dscp-session.pcapng`.> **Out of scope: user-facing DSCP notation.** Whether an implementation'sAddressed in 389c26b. The compact row now requires an otherwise-serviceable ECHO, specifies the normal Close-flagged reply and counted request, and names the rate-limited trigger exception.
Addressed in 389c26b. The compact row now applies only to an otherwise-serviceable ECHO that is the first tested packet to touch the expired session, and it points to Section 18.2 for normally dropped packets that can release it first.
Addressed in 389c26b. The wire and upstream distinction remains documented; the text now requires only implementations reproducing distinct upstream outcomes to retain enough request-validation information. It prescribes no decoded representation and permits clean policy to map adversarial forms to the same safe outcome.
@@ -627,0 +789,4 @@the configured minimum interval used by the tested limiter: when the configuredminimum exceeds (idle timeout ÷ 4), the negotiated interval is the smaller valuewhile reply allowance still replenishes on the larger configured interval. Aclient that sends at the interval it was given can therefore itself beAddressed in 389c26b. The measured 1499/1500 and 1279/1280 decision boundaries were retained; the claim that truncation occurred before policy was removed or labelled only as an inference because black-box evidence cannot establish that internal ordering.
@@ -609,0 +720,4 @@The loopback row establishes something weaker, and is not evidence of an exact16384-byte cap. All it shows is that lengths up to 8000 were emitted unclamped.The cap could not be approached there: on this host a reply beyond roughly 9300Addressed in 389c26b. Section 9.3 now distinguishes the configured minimum interval used by the tested limiter from the negotiated interval returned to the client; token-bucket wording is explicitly a black-box inference.
Addressed in 389c26b. The finding now states only that a malformed OPEN does not prevent a subsequent well-formed OPEN from succeeding; hidden retained, accounting, and parser state are left unspecified.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:
389c26bb6cℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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".
When the fill pattern length does not divide the payload length, resetting versus continuing the phase produces different reply bytes—the four 7-byte payloads immediately above demonstrate exactly that distinction—so a client or packet capture can observe which policy was chosen even though the payload has no protocol meaning. Fresh evidence after the earlier fill-state review is this newly added assertion that “nothing observable distinguishes” the alternatives; describe them as interoperability-equivalent instead of contradicting the measured phase observation.
AGENTS.md reference: AGENTS.md:L12-L14
Useful? React with 👍 / 👎.
When a maximum-duration deadline is crossed by an oversized, foreign-endpoint, truncated, or otherwise dropped request, these lines prescribe that the session remains live until the next served echo. The admitted Finding S-23 evidence exercises only a rate-limited request in the deadline-crossing position; the other two drop classes were tested only before the clock started, so their post-deadline behavior remains ambiguous. Fresh evidence after the earlier review is the new “such as” wording, which generalizes the rate-limit result to every independent drop reason; scope this statement to rate limiting rather than defining unmeasured lifecycle behavior.
AGENTS.md reference: AGENTS.md:L12-L14
Useful? React with 👍 / 👎.
Corrected in 11e8a9bf3fcffa6dd9ceb5ed4cd7fcf5c6144ee8. Section 15.2 now says only the tested rate-limited deadline-crossing Echo was silently dropped without Close, the session remained usable, and the next served Echo carried Close. It explicitly leaves the corresponding behavior of other independently dropped post-deadline classes untested and unspecified. The client specification stale generalization was narrowed to match.
Corrected in 11e8a9bf3fcffa6dd9ceb5ed4cd7fcf5c6144ee8. Section 13.3 now states that reset and continuation can produce different payload bytes, making phase policy observable in a packet capture, but are interoperability-equivalent because a conforming client cannot depend on payload phase. The verification report now says the same, and no fill-state arrangement or per-session-state prescription was added.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:
11e8a9bf3fℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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".
@@ -1442,3 +1715,3 @@| Gap since the previous accepted echo | First request after the gap | The request after that || Gap since the previous accepted echo | First otherwise-serviceable echo after the gap | Immediate follow-up ||---|---|---|| 5.0 s | answered | answered |When the client-to-server path is interrupted for longer than
idle timeout + 5 sbut recovers before a longer negotiated test duration ends, a conforming client does enter this state: Section 18.2 says upstream answers its first otherwise-serviceable echo after recovery, whereas an implementation using either permitted alternative here remains silent. Those are observably different outcomes, so the claim that no conforming client can tell and that every outcome is silence cannot justify making the behavior unrestricted; account for mid-test packet loss or narrow the classification accordingly.AGENTS.md reference: AGENTS.md:L20-L30
Useful? React with 👍 / 👎.
@@ -1732,0 +2229,4 @@configured to provide no timestamps at all restricts a requested non-noneStampAt to none (Section 11.4) and answers this absent-Clock session normally,without timestamps. A server restricted to a *single* timestamp leaves therestricted (effective) StampAt non-none and does **not** prevent the fault.For the 2-second case, the preceding observed-behavior table says a request at 7.1 seconds is still answered and only the immediately following request is dropped, so the 7.00-second entry cannot literally be the shortest gap whose request is “not served.” The boundary sweep evidently uses the follow-up probe to determine that the session was released; label this column as the shortest gap after which the follow-up is dropped, or record both probe outcomes, so readers do not implement immediate expiry at the listed boundary.
AGENTS.md reference: AGENTS.md:L20-L30
Useful? React with 👍 / 👎.
@@ -1732,0 +2255,4 @@**The specific policy is deliberately left open.** Rejecting the open, treatingthe absent Clock as a defined default, restricting StampAt to none for such asession, or some other resolution are all consistent with the recommendationWhen a foreign-endpoint packet arrives after the idle deadline, this new behavior says it releases the session, but Sections 8.1 and 15.1 still state without qualification that a foreign echo leaves the session intact and a foreign close does not remove it; the conformance summary likewise requires endpoint mismatches to be dropped without disturbing the session. Explicitly scope those older rules to live, non-expired sessions or cross-reference this expiry exception so implementers are not given opposite lifecycle requirements.
AGENTS.md reference: AGENTS.md:L20-L30
Useful? React with 👍 / 👎.
@@ -1442,3 +1715,3 @@| Gap since the previous accepted echo | First request after the gap | The request after that || Gap since the previous accepted echo | First otherwise-serviceable echo after the gap | Immediate follow-up ||---|---|---|| 5.0 s | answered | answered |Addressed in cbd75fd6bfb3a3cdb1cad5d5fd8f9c0f99d3aed1. The false “no conforming client can tell” claim was removed; a conforming client can observe the difference after sufficiently long mid-test client-to-server path loss and recovery. This was not promoted to a new unsupported RFC 2119 MUST; the clean implementation policy remains open.
@@ -1732,0 +2255,4 @@**The specific policy is deliberately left open.** Rejecting the open, treatingthe absent Clock as a defined default, restricting StampAt to none for such asession, or some other resolution are all consistent with the recommendationAddressed in cbd75fd6bfb3a3cdb1cad5d5fd8f9c0f99d3aed1. Live-session endpoint-mismatch behavior remains unchanged, while the text now scopes out and cross-references the separately observed expired-session release exception in Sections 8.1, 15.1, and 17; Finding S-1 now carries the same live-session scope.
@@ -1732,0 +2229,4 @@configured to provide no timestamps at all restricts a requested non-noneStampAt to none (Section 11.4) and answers this absent-Clock session normally,without timestamps. A server restricted to a *single* timestamp leaves therestricted (effective) StampAt non-none and does **not** prevent the fault.Addressed in cbd75fd6bfb3a3cdb1cad5d5fd8f9c0f99d3aed1. The timeout+5 values now describe the observed session-release boundary detected by the immediate follow-up probe, not a threshold at which the first post-gap request itself stops receiving a reply. The verification report and behavioral vectors use the same follow-up-based labels.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:
cbd75fd6bfℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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".
@@ -331,9 +344,12 @@ A server parses the whole parameter payload. Observed acceptance rules:| Duration present and ≤ 0 | **Dropped, no reply** |When the server is configured to provide no timestamps, Section 22.5 and the behavioral vector say it restricts the requested non-none
StampAtto none and serves this absent-Clock session normally. This unconditional admission-table row instead says every such request creates an unusable session whose first echo is fatal; qualify it for the default/single-timestamp policies or include the no-timestamp exception so the compatibility baseline does not prescribe opposite outcomes.AGENTS.md reference: AGENTS.md:L20-L30
Useful? React with 👍 / 👎.
@@ -1694,0 +2144,4 @@them. On the tested host, this failure was reachable in configurations whoseeffective reply cap exceeded the host's outbound datagram ceiling, including thetested loopback and wildcard cases. The tested 1500- and 1280-byte interface-boundlisteners could not reach it because their reply caps were lower. Jumbo interfacesWhen a nonconforming peer triggers this defect while well-behaved clients have sessions on the same process, the preceding lines state that every session stops being served, so those clients can observe whether the server survived. This does not make reproducing the crash an interoperability requirement, but the rationale should say that a conforming client cannot trigger the state rather than claiming the resulting outage is unobservable.
AGENTS.md reference: AGENTS.md:L18-L23
Useful? React with 👍 / 👎.
@@ -331,9 +344,12 @@ A server parses the whole parameter payload. Observed acceptance rules:| Duration present and ≤ 0 | **Dropped, no reply** |Addressed in 47bf6a2f0f563ca91365a13c4b97a67f01246fb9. The fatal absent-Clock result is now scoped to cases where restriction leaves the restricted (effective) StampAt non-none; the tested no-timestamp policy restricts StampAt to none and serves the session normally.
@@ -1694,0 +2144,4 @@them. On the tested host, this failure was reachable in configurations whoseeffective reply cap exceeded the host's outbound datagram ceiling, including thetested loopback and wildcard cases. The tested 1500- and 1280-byte interface-boundlisteners could not reach it because their reply caps were lower. Jumbo interfacesAddressed in 47bf6a2f0f563ca91365a13c4b97a67f01246fb9. Conforming clients cannot themselves trigger the malformed negotiation, but unrelated conforming clients can observe the resulting process-wide outage if another peer triggers it. Reproducing the crash remains a robustness defect, not an interoperability requirement.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:
47bf6a2f0fℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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".
@@ -1181,3 +1187,521 @@ disregards it loses nothing normative.**Classification:** SERVER SPEC CORRECTION (server spec Sections 9.2, 11.3.1,The experiments only establish this failure for the tested loopback/wildcard setup, so saying the reachable configurations are “exactly” loopback or wildcard overgeneralizes the evidence. A directly bound jumbo-MTU interface could also have a reply cap above the host's outbound datagram ceiling, and Section 23.5 explicitly leaves jumbo interfaces and other platforms untested; scope this to the observed configurations or state the actual condition that the reply cap exceeds the transmit ceiling.
AGENTS.md reference: AGENTS.md:L12-L14
Useful? React with 👍 / 👎.
@@ -28,17 +28,23 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT","RECOMMENDED", "MAY", and "OPTIONAL" are to be interpreted as interoperabilityThis definition says black-box inferences never describe an internal mechanism, but the document immediately uses that marker for a token-bucket mechanism in Section 9.3 and for lookup/creation-driven expiry rather than scheduled removal in Section 18.2. Those are appropriately qualified hypotheses, but they still describe mechanisms, so the statement-level definition contradicts its own uses; define the level as not asserting a mechanism as fact, or remove the mechanism descriptions.
AGENTS.md reference: AGENTS.md:L12-L14
Useful? React with 👍 / 👎.
The fresh text correctly acknowledges that a process-wide failure caused by another peer is observable to a conforming client, but the statement-level table in Section 1 still defines every robustness recommendation as something “no existing client can observe whether it was followed.” The new send-failure and accepted-parameter recommendations directly invalidate that blanket definition, so update the table to say these are non-interoperability requirements without claiming their effects are universally unobservable.
AGENTS.md reference: AGENTS.md:L20-L23
Useful? React with 👍 / 👎.
@@ -28,17 +28,23 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT","RECOMMENDED", "MAY", and "OPTIONAL" are to be interpreted as interoperabilityAddressed in 064b7d550107c7e4d10cd96c93796c8d2731e07b. The definition now permits explicitly labelled explanatory mechanism hypotheses, but does not treat those mechanisms as directly observed fact and keeps them non-load-bearing. Section 18.2 now also describes its expiry explanation as not directly measured.
@@ -1181,3 +1187,521 @@ disregards it loses nothing normative.**Classification:** SERVER SPEC CORRECTION (server spec Sections 9.2, 11.3.1,Addressed in 064b7d550107c7e4d10cd96c93796c8d2731e07b. “Exactly loopback or wildcard” was removed. The text now scopes the observed failure to the tested configurations and the effective reply-cap versus host transmit-ceiling condition; jumbo and other untested interfaces remain unresolved.
Addressed in 064b7d550107c7e4d10cd96c93796c8d2731e07b. The definition now says these are non-interoperability resilience/safety recommendations; their consequences may still be visible to conforming clients, consistent with Section 24.3.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:
064b7d5501ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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".
@@ -350,6 +366,74 @@ parameter payloads. A payload of over 200 bytes composed of unknown tags wasaccepted and answered normally. Any such limit in an implementation is a localThe vectors at
SERVER_BEHAVIORAL_VECTORS.mdlines 427–435 exercise an invalid occurrence in both positions only for Duration; Clock and ServerFill are tested only with the invalid value second, and the other known tags have no invalid-duplicate rows. Therefore the parser-wide claim that any invalid occurrence rejects regardless of position exceeds the admitted evidence and could misdirect an implementation whose validation differs by parameter type. Scope the position-independent rule to Duration and the explicitly tested rows, or label the broader conclusion as an inference/remaining ambiguity.AGENTS.md reference: AGENTS.md:L12-L14
Useful? React with 👍 / 👎.
@@ -1565,1 +1917,3 @@capture; see `BLACKBOX_VERIFICATION_REPORT.md` Finding B and**0–255**. It is not a 6-bit codepoint. For negotiated values in that range, aserver applies the value directly as the TOS / Traffic Class byte of its echoreplies, and a compatible implementation MUST encode and interpret it the sameFor an out-of-range DSCP value, these lines call the missing replies send failures while also establishing that the server continues serving its other sessions. Section 6.3, however, says a non-transient reply send failure terminates the listener and whole process. Black-box evidence supports only that these replies were absent and unrelated sessions stayed healthy; it cannot identify whether applying the marking failed before transmission or the send itself failed. State the observable outcome and leave the failure stage ambiguous, or explicitly distinguish this error class from the fatal send failures.
AGENTS.md reference: AGENTS.md:L12-L14
Useful? React with 👍 / 👎.
@@ -1732,0 +2255,4 @@**The specific policy is deliberately left open.** Rejecting the open, treatingthe absent Clock as a defined default, restricting StampAt to none for such asession, or some other resolution are all consistent with the recommendationWhen a foreign-endpoint packet is the first to touch an idle-expired session, these lines establish that it releases the session, but Section 24.1 item 7 still requires endpoint-check failures to be dropped “without disturbing the session.” Fresh evidence after the earlier review thread is that this unconditional summary remains at lines 2367–2368 in the final tree. Scope that requirement to live, non-expired sessions or cross-reference this expiry exception so implementers are not given contradictory lifecycle rules.
AGENTS.md reference: AGENTS.md:L20-L30
Useful? React with 👍 / 👎.
@@ -350,6 +366,74 @@ parameter payloads. A payload of over 200 bytes composed of unknown tags wasaccepted and answered normally. Any such limit in an implementation is a localAddressed in 221c38e166983b8c6ba691e163030986ad0ce1d6. Valid last-value-wins evidence remains broad across the nine tested known tags. Invalid-duplicate behavior is now scoped to Duration in both tested orders and the tested invalid-second Clock and ServerFill rows; untested orders and parameters are explicitly unspecified in the spec, vectors, verification report, and PR body.
@@ -1732,0 +2255,4 @@**The specific policy is deliberately left open.** Rejecting the open, treatingthe absent Clock as a defined default, restricting StampAt to none for such asession, or some other resolution are all consistent with the recommendationAddressed in 221c38e166983b8c6ba691e163030986ad0ce1d6. The final conformance checklist now scopes “session remains usable” to live, non-expired sessions and cross-references the separately observed expired-session release behavior in Section 18.2.
@@ -1565,1 +1917,3 @@capture; see `BLACKBOX_VERIFICATION_REPORT.md` Finding B and**0–255**. It is not a 6-bit codepoint. For negotiated values in that range, aserver applies the value directly as the TOS / Traffic Class byte of its echoreplies, and a compatible implementation MUST encode and interpret it the sameAddressed in 221c38e166983b8c6ba691e163030986ad0ce1d6. The docs now record only the observable result for DSCP >=256: OPEN succeeds, the affected session emits no observed ECHO reply, and unrelated sessions remain healthy. The exact failure stage is explicitly left unknown and is no longer called a verified send failure; it is distinguished from the fatal outbound send failure.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:
221c38e166ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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".
@@ -1181,3 +1187,521 @@ disregards it loses nothing normative.**Classification:** SERVER SPEC CORRECTION (server spec Sections 9.2, 11.3.1,Fresh evidence beyond the earlier specification fix is that this S-25 subheading remains unqualified: it says replies are capped at the bound interface's MTU, while the loopback result immediately below explicitly did not reach or observe its 16384-byte cap, and other platforms remain untested. Scope this heading to the measured Ethernet and tunnel interfaces, or describe only the observed effective boundary, so the evidence report does not present an unresolved host-specific rule as fact.
AGENTS.md reference: AGENTS.md:L12-L14
Useful? React with 👍 / 👎.
The body limits this comparison to the enumerated classes (
Every class tested), and the companion specification and vectors consistently call rate limiting the only tested drop class with this effect. Dropping that qualifier in the finding title turns the admitted comparison into a universal claim about all discard paths; retain “tested” here so unmeasured cases remain explicitly ambiguous.AGENTS.md reference: AGENTS.md:L12-L14
Useful? React with 👍 / 👎.
@@ -1181,3 +1187,521 @@ disregards it loses nothing normative.**Classification:** SERVER SPEC CORRECTION (server spec Sections 9.2, 11.3.1,Agreed — the heading outran its own body. Now reads "On the two interfaces where the cap was reachable, the emitted reply is capped at the bind interface's MTU", leaving the loopback row as the lower bound it is (lengths to 8000 unclamped; ~9300 ends the process before 16384 can be observed).
🤖 Addressed by Claude Code
@@ -1181,3 +1187,521 @@ disregards it loses nothing normative.**Classification:** SERVER SPEC CORRECTION (server spec Sections 9.2, 11.3.1,Agreed — the title was the only place missing the qualifier the body, the spec and the vectors all carry. Finding S-20 is now "the only tested drop class that keeps a session alive".
🤖 Addressed by Claude Code
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:
3f02372f5bℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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".
@@ -1181,3 +1187,521 @@ disregards it loses nothing normative.**Classification:** SERVER SPEC CORRECTION (server spec Sections 9.2, 11.3.1,The sweeps cover only idle timeouts of 500 ms, 2 s, and 4 s and maximum durations of 500 ms, 1 s, and 3 s, so they establish constant margins across those tested settings—not across the entire configurable value domain. Calling both margins constant across “the configured value” promotes a three-point observation into an unrestricted rule; qualify the conclusion to the measured values or label the broader extrapolation as an inference/remaining ambiguity.
AGENTS.md reference: AGENTS.md:L12-L14
Useful? React with 👍 / 👎.
@@ -1356,6 +1626,7 @@ token**, and the fully restricted parameter payload.| Subsequent close with the zero token | Dropped, no reply |The admitted experiment only shows that a burst of ordinary opens caused the expired session to disappear before the subsequent probe; it does not establish that one ordinary open always reclaims an expired session rather than reclamation depending on a threshold or another batch condition. This row turns that batch outcome into a per-request invariant, so describe only the tested burst or leave single-open behavior ambiguous.
AGENTS.md reference: AGENTS.md:L12-L14
Useful? React with 👍 / 👎.
@@ -1566,3 +1921,4 @@wire, not 46. Verified by capture; see `BLACKBOX_VERIFICATION_REPORT.md` Finding B and`captures/dscp-session.pcapng`.> **Out of scope: user-facing DSCP notation.** Whether an implementation'sThe admitted negative-marking evidence identifies only
DSCP = -1producing IPv4 TOS 255 (the older-5row records delivery but not the emitted TOS). That single mapping cannot distinguish modulo-256 conversion from clamping, special-case handling, or another platform behavior, so describing it as “the value taken modulo 256” asserts an unmeasured transformation. State only-1 → 255or label modulo conversion as an inference.AGENTS.md reference: AGENTS.md:L12-L14
Useful? React with 👍 / 👎.
@@ -1356,6 +1626,7 @@ token**, and the fully restricted parameter payload.| Subsequent close with the zero token | Dropped, no reply |Agreed — only the burst was tested. §18.2 now reads "A burst of ordinary opens released an expired session; a burst of no-test opens did not", and states that whether a single open suffices, or whether a count/rate matters, was not measured. The §16 row now compares burst with burst rather than implying a per-open invariant.
🤖 Addressed by Claude Code
@@ -1181,3 +1187,521 @@ disregards it loses nothing normative.**Classification:** SERVER SPEC CORRECTION (server spec Sections 9.2, 11.3.1,Agreed — three swept points each. Finding S-22 now names the settings, says the sweeps rule out a margin proportional to the configured value over the range tested (which is what "additive" means here), and records that a threshold or different behavior outside that range would not have shown up and stays untested.
🤖 Addressed by Claude Code
@@ -1566,3 +1921,4 @@wire, not 46. Verified by capture; see `BLACKBOX_VERIFICATION_REPORT.md` Finding B and`captures/dscp-session.pcapng`.> **Out of scope: user-facing DSCP notation.** Whether an implementation'sAgreed — modulo-256, clamping to the byte range and a −1 special case all predict TOS 255 for the one negative value whose marking was recorded. The spec and the vector now state the −1 → 255 mapping and say the transformation is not identified; Part IV already avoided the modulo claim.
🤖 Addressed by Claude Code
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:
7f5d252520ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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".
@@ -1181,3 +1187,521 @@ disregards it loses nothing normative.**Classification:** SERVER SPEC CORRECTION (server spec Sections 9.2, 11.3.1,In this trial the foreign-endpoint packet receives no reply and the session is already unavailable when every later probe arrives, so no emitted statistic reveals whether that packet changed the received count before release. The earlier live-session endpoint test does not establish counter handling on this distinct expired-session path; retain the observed drop and release outcome, but leave whether it was internally counted ambiguous.
AGENTS.md reference: AGENTS.md:L12-L14
Useful? React with 👍 / 👎.
@@ -1573,28 +1929,108 @@ capture; see `BLACKBOX_VERIFICATION_REPORT.md` Finding B and> upstream wire behavior, and it does not belong in this specification.Clamping
-1to the byte range0..=255produces0, not255, so the observed IPv4 mapping actually distinguishes ordinary clamping from modulo-256 conversion. Keeping clamping in this list makes the stated ambiguity mathematically incorrect; remove it or define the different conversion that was intended.AGENTS.md reference: AGENTS.md:L12-L14
Useful? React with 👍 / 👎.
@@ -1573,28 +1929,108 @@ capture; see `BLACKBOX_VERIFICATION_REPORT.md` Finding B and> upstream wire behavior, and it does not belong in this specification.You are right and my arithmetic was wrong — clamping −1 into
0..=255gives 0, so the observation excludes clamping rather than leaving it ambiguous. The candidates are now the low byte of the two's-complement representation (equivalently the value modulo 256) and a special case for this input, and the text records that plain clamping is ruled out because it would have emitted 0.🤖 Addressed by Claude Code
@@ -1181,3 +1187,521 @@ disregards it loses nothing normative.**Classification:** SERVER SPEC CORRECTION (server spec Sections 9.2, 11.3.1,Agreed — the session emitted no further reply, so no statistic can report whether that packet advanced the count. Finding S-1's not-counted result was measured on a live session where a later reply exposed the count, and I was carrying it onto a path where it does not apply. The report and the vector now state the release outcome and leave the counting question open; spec §18.2 already avoided the claim.
🤖 Addressed by Claude Code
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:
629ead0832ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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".
@@ -1181,3 +1187,521 @@ disregards it loses nothing normative.**Classification:** SERVER SPEC CORRECTION (server spec Sections 9.2, 11.3.1,When a server-initiated Close is sent for a session with nonzero DSCP, the recorded evidence does not establish that it retains the mark:
server-dscp-interleaved.pcapngcontains only ordinary echo replies, whileserver-close.pcapnguses TOS 0 throughout. Calling the Close reply an ordinary marked echo assumes that setting the flag cannot affect marking; either document an observed nonzero-DSCP Close exchange or leave this behavior ambiguous rather than making it normative elsewhere.AGENTS.md reference: AGENTS.md:L12-L14
Useful? React with 👍 / 👎.
When another peer triggers this defect, these lines explicitly say unrelated conforming clients observe the process-wide outage, contradicting Section 22's premise at lines 2106–2109 that no conforming client can tell which robustness choice was made. Fresh evidence after the prior review is that this blanket sentence remains in the final tree alongside the newly documented counterexample; qualify it to the triggering exchange or internal cause rather than all externally visible consequences.
AGENTS.md reference: AGENTS.md:L20-L23
Useful? React with 👍 / 👎.
@@ -1181,3 +1187,521 @@ disregards it loses nothing normative.**Classification:** SERVER SPEC CORRECTION (server spec Sections 9.2, 11.3.1,Confirmed by checking every admitted capture — none contains a Close-flagged reply with nonzero TOS, and
server-close.pcapngis TOS 0 throughout because that session negotiated no DSCP. The marking is a measured result, so I kept it but dropped the "ordinary marked echo reply that also sets the Close flag" clause (it argued from the flag rather than reporting the observation) and both tables now state that no capture shows it. Nothing normative depended on it: §15.2 and §24 make no marking claim.🤖 Addressed by Claude Code
Agreed — §22's preamble contradicted its own §22.1 and §22.5. It now rests the classification on what a conforming client can provoke: it cannot reach these outcomes and nothing about the wire is required, but the consequences are plainly visible to clients sharing the process. (The §1 statement-level table was fixed for the same defect earlier; this was the remaining site.)
🤖 Addressed by Claude Code