Skip to content

fix(j1939tp): bind BAM steps to their session, keep T3 on a CTS hold, validate timers - #258

Merged
dborgards merged 5 commits into
mainfrom
fix/j1939tp-bam-session-identity
Oct 2, 2026
Merged

dborgards merged 5 commits into
mainfrom
fix/j1939tp-bam-session-identity

Conversation

@dborgards

Copy link
Copy Markdown
Owner

What does this change?

Closes three J1939-TP defects from the 2026-09-30 deep review (findings T1, T2 and the J1939-TP half of I8); the review has the mechanism and file/line for each. A cancelled BAM no longer drives the next BAM of the same PGN (it produced a duplicate TP.DT 1 and a reported success), a CTS hold after the last TP.DT no longer strips the send of every timer, and non-positive timers are rejected at Open instead of hanging a send.

Type of change

  • feat — new behaviour (minor release)
  • fix / perf — bug or performance fix (patch release)
  • docs / test / refactor / chore / ci — no release
  • Breaking change (! in the title, plus a BREAKING CHANGE: footer explaining the migration)

Checklist

  • dotnet build CanKit.Pro.sln -c Release succeeds (with -p:CI=true)
  • dotnet test CanKit.Pro.sln -c Release passes (net10.0, --no-build)
  • Public API changes are documented with XML comments — none, Validate is internal
  • New behaviour is covered by a test — one per fix, each seen to fail with that fix alone removed
  • The requirement or ADR this relates to is referenced — FR-TP-032 (timers, abort)

Also run: dotnet format --verify-no-changes, dotnet pack + eng/verify-packages.py.

Notes

  • Behaviour change to be aware of: T1..T4 equal to zero were accepted before and fired on the next loop iteration; they are now rejected with ArgumentOutOfRangeException, as are negative values. A zero BamPacketSpacing stays valid. I classified this as a fix, not a breaking change, because zero timers have no useful meaning for the protocol timers; say if you read it differently.
  • Deliberately not in this PR: the other J1939-TP findings (T3 bidirectional abort, minor items), which need a normative decision or are separate.

🤖 Generated with Claude Code

… validate timers

Three defects from the 2026-09-30 deep review (docs/reviews/2026-09-30-deep-review.md,
findings T1, T2 and the J1939-TP half of I8).

A BAM chain was addressed by its (destination, PGN) key only. Cancelling a BAM and
sending the same PGN again inside the packet spacing left the first session's timer
armed; it then drove the new session, so TP.DT 1 went out twice, a conforming receiver
aborted, and the sender reported success. Each step now carries its session and acts
only while that instance is the registered one.

A CTS with numPackets = 0 replaced the running timer with T4 in every state, but T4's
expiry is ignored outside WaitCts. After the last TP.DT that left the send with no
timer at all, holding its slot and blocking every later send to that destination. The
hold now only takes effect while the sender waits for a CTS; otherwise T3 keeps running.

T1..T4 and BamPacketSpacing were not validated. A negative value made Arm throw after
the session was registered and the RTS sent, again leaving a send without a deadline.
T1..T4 must now be greater than zero and BamPacketSpacing not negative, rejected at Open.

Each fix has a regression test that was seen to fail with that fix removed.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@cursor

cursor Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

PR Summary

Medium Risk
Changes core TX state machines (BAM chaining and CM timer arming) where mistakes could stall destinations or abort valid transfers; behavior is heavily tested but still protocol-critical.

Overview
Fixes three J1939 transport bugs: cancelled or superseded BAM sends no longer leak spacing timers or let stale confirmations drive a later send with the same PGN, CTS(0) holds no longer wipe the active deadline when they arrive at the wrong stage, and invalid timer options fail at channel open instead of mid-send.

BAM lifecycle: BAM announce/DT continuations now carry the TxSession instance and gate on IsCurrentBamSession so a replaced session under the same key is ignored. Packet-spacing schedules are stored on SpacingTimer and disposed in EndTx / Fail, so cancel, dispose, and long spacing cannot leave ghost DTs or pinned payloads.

Connection-mode CTS hold: numPackets == 0 only swaps in T4 while the sender is in WaitCts. Holds that race the last DT of a block set HoldPending and apply T4 when the block completes; holds after the final DT or mid-block are ignored so T3 for EndOfMsgAck (or post-block CTS) stays armed.

Options: J1939TpOptions.Validate() rejects T1–T4 ≤ 0 and negative BamPacketSpacing (zero spacing remains allowed).

Regression tests cover BAM cancel/replace races, hold timing edge cases, and option validation.

Reviewed by Cursor Bugbot for commit 570ab7b. Bugbot is set up for automated code reviews on this repo. Configure here.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-01T20:56:59.477077Z 570ab7b New commits
ℹ️ About Codex in GitHub

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

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

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f47212c598

ℹ️ About Codex in GitHub

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

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

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

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

Comment thread src/CanKit.Pro.J1939Tp/J1939TpChannel.cs Outdated
@codecov

codecov Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.59459% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/CanKit.Pro.J1939Tp/J1939TpChannel.cs 92.59% 0 Missing and 2 partials ⚠️

📢 Thoughts on this report? Let us know!

A CTS(0) that arrives right after the last DT of a block, before its confirmation has
run, was dropped by the SendingDt guard, and the confirmation then armed T3. Remember
the hold (not for the message's last packet, where T3 for the EndOfMsgAck is right) and
arm T4 when the block ends; a CTS that grants packets clears it.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ece32923c0

ℹ️ About Codex in GitHub

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

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

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

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

Comment thread src/CanKit.Pro.J1939Tp/J1939TpChannel.cs Outdated
The spacing timer of a BAM captures its session and so its payload; the handle was
discarded, so a cancelled BAM stayed reachable until the timer fired, which with a long
BamPacketSpacing is as long as that value. The session now holds the handle and EndTx
releases it.

Tests: the timer is gone after a cancel; a late announce confirmation of a cancelled BAM
cannot start the next BAM of the same PGN (the instance check, alone); a CTS hold while
the last packet is outstanding leaves T3 for the EndOfMsgAck. The hold bookkeeping from
the previous commit drops a condition that never had an effect.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 0f11527. Configure here.

Comment thread src/CanKit.Pro.J1939Tp/J1939TpChannel.cs Outdated
The channel ends its sessions through TxSession.Fail on dispose, not through EndTx, so a
BAM in flight on a borrowed actor kept its spacing timer, session and payload until the
interval elapsed. Release it in Cancel and Fail as well, behind one method.

Also drops the redundant IsCm test from the current-session check (only BAM steps call
it) and adds coverage for a late TP.DT confirmation of a cancelled BAM.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Comment thread tests/CanKit.Pro.Tests/TestCases/J1939TpTests.cs Fixed
…confirmation with no successor

Takes back the release line in TxSession.Cancel, which nothing calls (only RxSession.Cancel
is used), so it only added an uncovered line.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@dborgards
dborgards merged commit 4991be2 into main Oct 2, 2026
14 checks passed
@dborgards
dborgards deleted the fix/j1939tp-bam-session-identity branch October 2, 2026 03:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants