8000 spec(I15): bounded, declared recovery -- Failure Modes & Recovery in all 75 micro-specs (338 failure modes, 193 DEFECT, 144 GAP) + failure-mode tests by minguyen9988 · Pull Request #1535 · Altinity/clickhouse-sink-connector · GitHub
[go: up one dir, main page]

Skip to content 8000

spec(I15): bounded, declared recovery -- Failure Modes & Recovery in all 75 micro-specs (338 failure modes, 193 DEFECT, 144 GAP) + failure-mode tests - #1535

Merged
minguyen9988 merged 24 commits into
fix-binlog-connection-guard-chaos-testsfrom
spec-bounded-declared-recovery
Oct 1, 2026
Merged

minguyen9988 merged 24 commits into
fix-binlog-connection-guard-chaos-testsfrom
spec-bounded-declared-recovery

Conversation

@minguyen9988
Copy link
Copy Markdown
Collaborator

Stacked on #1534; it retargets to 2.11.0 when #1534 merges.

  • Constitution Invariant I15, Bounded, Declared Recovery (Minutes, Not Hours). Every failure must be detected loudly within a stated bound, recovered by a declared procedure that never trades correctness for speed, and resolved within an RTO of 5 minutes plus the re-apply of the one in-flight transaction. Each failure mode is declared with its detection, blast radius, recovery, RTO (measured or unmeasured) and test, or an explicit GAP. Anything silent, unbounded or past the RTO is recorded as a DEFECT. The Smart Ralph protocol now requires the section.
  • Validator: every micro-spec must have a Failure Modes section containing Detection, Recovery and RTO, and every test it cites must exist. There are 3 new self-tests.
  • All 75 micro-specs now carry the section: 338 failure modes, 193 DEFECT, 144 GAP. Each entry is grounded in the 2.11.0 code; library behaviour was checked in the Debezium 3.1.3 and client-v2 0.9.8 jars, or is marked unverified.
  • 51 new test files (Java core and lightweight, Python tools). Tests that pin current behaviour pass. Tests that pin a DEFECT are disabled or skipped with the FM id, and each one was run enabled and confirmed to fail on 2.11.0.

The DEFECTs that matter most for bounded recovery:

  • Retriable and unknown batch failures retry forever with WARN only, and the lag gauge freezes: 03.03, 10.04.
  • The connector's own refusals, and several ClickHouse parse errors, are classified UNKNOWN and retried forever: 05.02, 07.x, 12.x.
  • executeSystemQuery returns normally after its retries run out, so a DDL that never ran is acknowledged: 06.08, 08.01.
  • The REST position edit deletes the offset row and inserts the new one into a table of the system database: 09.03-4. With enable.snapshot.ddl=true, the next start then empties the replica.
  • client-v2 socket_timeout is 0, so a half-open ClickHouse connection hangs an INSERT forever: 03.06-1.
  • A GC death spiral never exits: 01.05, 01.01.
  • History-mode redelivery loses versions: 12.03.
    Fixes follow in separate PRs.

Checks: validate_specs.py passes (75 specs, 1173 citations). Core 738 run, 0 failures, 41 disabled DEFECT tests skipped. Lightweight 695 run, 0 failures, 28 skipped. Errors appear only in Docker-only classes. Python tools: 154 passed, 5 skipped.

minguyen9988 and others added 24 commits September 30, 2026 11:04
…s failure modes with Detection, Recovery and RTO; the validator requires the section and checks the tests it cites
…onitoring domains (specs 08.x, 10.x) -- passing pins plus @disabled DEFECT tests confirmed red on 2.11.0

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…parser, translation, execution and PK rebuild

Adds section 6 Failure Modes & Recovery to all nine specs of 06-ddl-replication
(42 failure modes, 23 DEFECT, 12 GAP) and pure unit tests pinning them:
DdlFailureModesTest, DdlTranslationFailureModesTest,
DBMetadataExecuteSystemQu
8000
eryExhaustionTest, ClickHouseBatchExecutorInterruptTest.
Eight tests are @disabled DEFECT pins that fail on 2.11.0, among them
FM-06.08-2: DBMetadata.executeSystemQuery returns normally after exhausting
retries, so a DDL refused with any retryable ClickHouse code (or sent while
ClickHouse is down) is acknowledged as applied. No src/main change.

Destructive-Op-Check: sites=8; result=pass
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…, terminal vs retried-forever refusals, operator recovery procedures; new poison-value tests (enabled pins + disabled DEFECT tests)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…_compare, Lean suite, ch-mysql-resync, Python tool coverage; offline tests pinning each mode, DEFECTs as skipped tests

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…-02.06 declare 20 failure modes with detection, recovery and RTO; 15 DEFECTs, the code-level ones pinned by disabled tests (counter carry at reset, in-process restart redelivery, same-name failover, GTID domain switch and 22-bit tie-break, future mark after a clock step, underivable version retried)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…- 09.01-09.04 declare 18 failure modes with detection, recovery and RTO; 11 DEFECTs, among them the REST position edit that deletes the offset row and inserts into system.<table>, offset flush failures reported only at WARN, and stale or missing offsets turning a restart into an unbounded replay or reload

Destructive-Op-Check: sites=1; result=pass
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…alog and resilience/monitoring: out-of-band ClickHouse DDL, stale-cache probe failure, partial writer init, silent catalog-DDL retry exhaustion, forever-retry liveness gap, frozen lag signals, PostgreSQL status view, dedup retried-put loss

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…y mutation -- worker Error death, 252/241 retry, partial-write retry, chunk failure; disabled DEFECT tests for unbounded retry, interrupted pause, refusals classified UNKNOWN, ignore_delete tombstone, EXECUTE_FAILED, sorting-key read failure, retired endpoint, override map validator, thread.pool.size=0, binary key token, collapsing sign parsing

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… -- worker death, unbounded retry, pool retirement and keep-alive, hung INSERT, key-routing part pressure and TRUNCATE barrier

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…I15) -- sorting-key read failure and drift, ignore_delete tombstone, refusals retried forever, CollapsingMergeTree replay and sign parsing

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… 01.01-01.07, 33 failure modes, 15 DEFECT, 14 GAP

Adds the Failure Modes & Recovery section to the engine lifecycle, binlog coordinates, dispatch loop, transaction boundaries, handoff, control records and keep-alive/reconnect specs, with behaviour read from the 2.11.0 code and from the Debezium 3.1.3 / binlog client 0.40.2 bytecode. New unit tests: 4 passing pins (source clock steps, interrupted handoff, transient source loss) and 7 @disabled DEFECT tests that fail on 2.11.0 (restart-monitor clock, heartbeat liveness, DDL dropped on ignore-rule failure, blocked put behind a dead worker, purged binlog and poison row retried as transient, byte-cap first-row sampling).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…atting/membership/update/truncate/memo failure modes; new tests for N:1 database fan-in and failed staleness re-read

Destructive-Op-Check: sites=1; result=pass

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…SCD2 shape, SCD2 write protocol, audit table, replication-log-only; redelivery, poison and routing tests (DEFECTs disabled)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ExecutorInterruptTest: FM-03.01-4 and FM-06.02-1 pin one code path; both methods kept in one class)

Destructive-Op-Check: sites=8; result=pass
…that is not part of this change

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@minguyen9988
minguyen9988 merged commit b780d32 into fix-binlog-connection-guard-chaos-tests Oct 1, 2026
12 checks passed
@minguyen9988
minguyen9988 deleted the spec-bounded-declared-recovery branch October 1, 2026 02:41
minguyen9988 added a commit that referenced this pull request Oct 1, 2026
…rollback reported; chaos and edge harnesses with measured recovery times (Specs 01.08 section 6, 01.09, 01.10) (#1534)

* fix(binlog): every dead binlog connection restarts the engine instead of stalling silently; XA rollbacks after PREPARE are reported; chaos, stress and edge harnesses for compressed binlogs with measured recovery times (Specs 01.08 section 6, 01.09, 01.10)

Binlog connection guard (spec 01.09): with connect.keep.alive=false a source-side close (mysqld killed, failover) ended the binlog client's read loop as a normal end and a connection that died behind a partition blocked the reader forever; both left replication stopped with no ERROR (measured: 15 min and 300 s without recovery). The binlog socket now turns end of stream into an EOFException and carries a read timeout (binlog.read.timeout.ms, default 2x connect.keep.alive.interval.ms, above the source heartbeat), installed through the connector's copy of Debezium's MySqlStreamingChangeEventSourceMetrics. Measured: mysqld kill -9 recovered in 5-10 s, a partition in 14 s, an idle source 200 s with zero restarts.

XA audit (spec 01.10): Debezium dispatches an XA transaction's rows at PREPARE and ignores XA ROLLBACK; the rollback is now an ERROR naming the tables plus a metric, fed from the client listener and, for compressed transactions, from the payload decoder's first pass. binlog_row_value_options=PARTIAL_JSON is dec
94DE
lared not supported (doc/limitations.md).

Harnesses: tests/e2e/binlog_transaction_compression_chaos.sh (12 fault phases under an 8-session writer mix, 30/30 GTID on and off), binlog_transaction_compression_edge.sh (8 edge cases, through the source and through a MySQL replica hop). Unit suites: lightweight 643 run, 0 failures (2 errors are Docker-only classes); core 663 run, 0 failures (20 Docker-only errors). The three e2e shell scripts contain docker --format Go-template placeholders, not Jinja; each was linted with bash -n.

Jinja-Render-Check: rendered=3; formats=shell; result=pass

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(binlog): review round -- a missing binlog client at guard/audit install is a WARN, not a silent no-op; the read-timeout ERROR reports the socket's own timeout; an XA ROLLBACK whose PREPARE predates the start says so; partial JSON through a replica hop and the OOM crash loop documented as measured (Specs 01.08 section 6, 01.09, 01.10)

Measured on the replica-hop edge run: a MySQL replica re-logs applied partial JSON updates with full row images (its own binlog_row_value_options), so a connector reading such a replica receives them; a 256 MiB row exhausted a 4 GiB heap in 4 of 6 runs and one restart looped on OOM.

Jinja-Render-Check: rendered=1; formats=shell; result=pass

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* spec(I15): bounded, declared recovery -- Failure Modes & Recovery in all 75 micro-specs (338 failure modes, 193 DEFECT, 144 GAP) + failure-mode tests (#1535)

* spec(I15): bounded, declared recovery -- every micro-spec declares its failure modes with Detection, Recovery and RTO; the validator requires the section and checks the tests it cites

* test(I15): failure-mode tests for the schema catalog and resilience/monitoring domains (specs 08.x, 10.x) -- passing pins plus @disabled DEFECT tests confirmed red on 2.11.0

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* spec(06): failure modes and recovery (Invariant I15) -- DDL barrier, parser, translation, execution and PK rebuild

Adds section 6 Failure Modes & Recovery to all nine specs of 06-ddl-replication
(42 failure modes, 23 DEFECT, 12 GAP) and pure unit tests pinning them:
DdlFailureModesTest, DdlTranslationFailureModesTest,
DBMetadataExecuteSystemQueryExhaustionTest, ClickHouseBatchExecutorInterruptTest.
Eight tests are @disabled DEFECT pins that fail on 2.11.0, among them
FM-06.08-2: DBMetadata.executeSystemQuery returns normally after exhausting
retries, so a DDL refused with any retryable ClickHouse code (or sent while
ClickHouse is down) is acknowledged as applied. No src/main change.

Destructive-Op-Check: sites=8; result=pass
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* spec(07): failure modes and recovery (Invariant I15) -- poison values, terminal vs retried-forever refusals, operator recovery procedures; new poison-value tests (enabled pins + disabled DEFECT tests)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* spec(11): failure modes and recovery (Invariant I15) -- validator, db_compare, Lean suite, ch-mysql-resync, Python tool coverage; offline tests pinning each mode, DEFECTs as skipped tests

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* spec(versioning): failure modes and recovery (Invariant I15) -- 02.01-02.06 declare 20 failure modes with detection, recovery and RTO; 15 DEFECTs, the code-level ones pinned by disabled tests (counter carry at reset, in-process restart redelivery, same-name failover, GTID domain switch and 22-bit tie-break, future mark after a clock step, underivable version retried)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* spec(offset-management): failure modes and recovery (Invariant I15) -- 09.01-09.04 declare 18 failure modes with detection, recovery and RTO; 11 DEFECTs, among them the REST position edit that deletes the offset row and inserts into system.<table>, offset flush failures reported only at WARN, and stale or missing offsets turning a restart into an unbounded replay or reload

Destructive-Op-Check: sites=1; result=pass
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* spec(08,10): failure modes and recovery (Invariant I15) -- schema catalog and resilience/monitoring: out-of-band ClickHouse DDL, stale-cache probe failure, partial writer init, silent catalog-DDL retry exhaustion, forever-retry liveness gap, frozen lag signals, PostgreSQL status view, dedup retried-put loss

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* test(I15): failure-mode tests for the execution engine and sorting-key mutation -- worker Error death, 252/241 retry, partial-write retry, chunk failure; disabled DEFECT tests for unbounded retry, interrupted pause, refusals classified UNKNOWN, ignore_delete tombstone, EXECUTE_FAILED, sorting-key read failure, retired endpoint, override map validator, thread.pool.size=0, binary key token, collapsing sign parsing

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* spec(03-execution-engine): failure modes and recovery (Invariant I15) -- worker death, unbounded retry, pool retirement and keep-alive, hung INSERT, key-routing part pressure and TRUNCATE barrier

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* spec(05-sorting-key-mutation): failure modes and recovery (Invariant I15) -- sorting-key read failure and drift, ignore_delete tombstone, refusals retried forever, CollapsingMergeTree replay and sign parsing

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* spec(cdc-engine): failure modes and recovery (Invariant I15) -- specs 01.01-01.07, 33 failure modes, 15 DEFECT, 14 GAP

Adds the Failure Modes & Recovery section to the engine lifecycle, binlog coordinates, dispatch loop, transaction boundaries, handoff, control records and keep-alive/reconnect specs, with behaviour read from the 2.11.0 code and from the Debezium 3.1.3 / binlog client 0.40.2 bytecode. New unit tests: 4 passing pins (source clock steps, interrupted handoff, transient source loss) and 7 @disabled DEFECT tests that fail on 2.11.0 (restart-monitor clock, heartbeat liveness, DDL dropped on ignore-rule failure, blocked put behind a dead worker, purged binlog and poison row retried as transient, byte-cap first-row sampling).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* spec(04): failure modes and recovery (Invariant I15) -- grouping/formatting/membership/update/truncate/memo failure modes; new tests for N:1 database fan-in and failed staleness re-read

Destructive-Op-Check: sites=1; result=pass

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* spec(12): failure modes and recovery (Invariant I15) -- mode matrix, SCD2 shape, SCD2 write protocol, audit table, replication-log-only; redelivery, poison and routing tests (DEFECTs disabled)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* spec(I15): drop the forward reference to a consolidated runbook spec that is not part of this change

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* test: neutral target database names in DatabaseOverrideValidatorTest

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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

0