Skip to content

feat(source): v1 hardening — tx-Term contract, dependency isolation, test-gap closure - #203

Merged
joshua-temple merged 2 commits into
mainfrom
feat/source-v1-hardening
Aug 23, 2026
Merged

feat(source): v1 hardening — tx-Term contract, dependency isolation, test-gap closure#203
joshua-temple merged 2 commits into
mainfrom
feat/source-v1-hardening

Conversation

@joshua-temple

Copy link
Copy Markdown
Collaborator

Checkpoint 3/5 — P2 decisions + dependency isolation on the road to source/v1.0.0

Stacked after #199 (merged) and #200 (merged); rebased onto current main.

P2-9 — transactional inlet + Term/DLQ: decided, implemented, documented

Direct Settle(Term) on a WithTransactional subscription is rejected with the new exported ErrTermInsideTransaction (a DLQ produce outside the open EOS session would break atomicity with the offset mark). The supported poison path is inside Transactional.Begin: produce the rejected record to the DLQ topic via the handed source.Tx, return success — DLQ record + consumed offset commit atomically. Documented in package doc, README divergence section, and Begin's doc comment.

P2-7 — Hopper.exitErr drops its ignored ctx parameter (unexported; no API change).

P2-8 — integration deps isolated out of downstream module graphs

The RedPanda leg moves to its own test-only nested module source/kafka/integration (own go.mod/go.sum). source/kafka/go.mod now requires only franz-go(+kmsg)+source; testcontainers-go/redpanda/kadm appear nowhere downstream. Workflow matrix + mage Integration target follow the new path; -tags integration convention and Docker-skip guard kept.

Test gaps closed (E)

  • Drain-on-cancel with mid-flight backend settle: Close+cancel race → exactly one settle, zero post-Close yields, goroutines return to baseline.
  • Duplicate-settle idempotence on both adapters: memsource (ledger coherent, still drains) + kafka (marks broker-idempotent).
  • Rebalance revoke-with-in-flight end-to-end on RedPanda: two group members join/leave; 40 records delivered exactly once across the group (pins onRevoked commit).
  • tx-Term pair: rejection sentinel + Begin DLQ pattern choreography.

Also fixes govet/shadow warnings in checkpoint 1's drain tests.

Evidence (local, this branch)

Check Result
source vet/build/race/fuzz-smoke(×2)/memsource race ok
source/kafka GOWORK=off vet/race ok
integration suite (Docker 28.4.0) incl. new rebalance test ×2 runs ok (17.6s / 29.5s)

Regressions vs baseline: none. API additions beyond approved list: ErrTermInsideTransaction only (required by the P2-9 decision).

…test-gap closure

P2-9 (decided + implemented + documented): settling Term directly on a
transactional subscription is rejected with the new exported
ErrTermInsideTransaction — a DLQ produce outside the open EOS session would
break atomicity with the consumed offset. The supported poison path is inside
Transactional.Begin: produce to the dead-letter topic via the handed Tx and
return success, committing DLQ record and offset atomically. Documented in
kafka.go, README divergence section, Begin doc; pinned by unit tests for both
the rejection and the Begin DLQ pattern.

P2-7: Hopper.exitErr drops its ignored ctx parameter.

P2-8: the RedPanda integration leg moves to its own test-only nested module
source/kafka/integration with its own go.mod, so testcontainers-go, redpanda,
and kadm no longer appear in source/kafka's require block and downstream module
graphs stop inheriting them. Workflow matrix and mage Integration target follow
the new path; the -tags integration convention and Docker-skip guard are kept.

P2-10/P2-11 comments landed with checkpoint 1 (requeue cost model; poll-error
record discard).

Test gaps closed: drain-on-cancel with mid-flight backend settle (Close+cancel
race: exactly one settle, zero post-Close yields, no stranded goroutines);
duplicate-settle idempotence on both adapters (memsource ledger + kafka marks);
rebalance revoke-with-in-flight end-to-end on RedPanda (two members join/leave,
40 records delivered exactly once across the group); tx-Term pair above.
Also fixes vet shadow warnings in checkpoint-1's drain tests.
The nested module's manifest was created after the checkpoint branch's initial
commit and missed the git add, so CI's source/kafka/integration leg had no
module definition. tidy run via GOFLAGS=-tags=integration so the
build-tag-gated testcontainers/redpanda/kadm imports keep their requirements.
@joshua-temple
joshua-temple merged commit fd296c8 into main Aug 23, 2026
121 checks passed
@joshua-temple
joshua-temple deleted the feat/source-v1-hardening branch August 23, 2026 03:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant