rivet-cli 0.22.0

Rivet: PostgreSQL/MySQL/SQL Server/MongoDB → Parquet/CSV (local, S3, GCS, Azure). Crate name rivet-cli; binary rivet.
Documentation
# Config-validation matrix — the ACCEPT-BUT-BREAK class: a config that PASSED
# validation but then broke, silently degraded, or misbehaved at runtime. Round-2
# found a cluster (#14/#15/#16/#17/#5/#6): chunk knobs silently ignored outside
# `mode: chunked` (degrading to an unbounded snapshot — the exact source-pressure
# footgun chunked mode prevents), partition_by combos that passed `rivet check`
# then died after a live probe, a documented mutual-exclusion left unenforced.
#
# The invariant: every gated knob/combo is REJECTED at CONFIG-LOAD (so `rivet check`
# and `rivet run` agree and nothing silently degrades) — AND a legit config is NOT
# false-rejected. This ledger drift-guards both halves (tests/offline/
# chunking_matrix_guard.rs).
#
# Two columns:
#   rejected_wrong_mode — a test asserts the accept-but-break combo is rejected at
#                         config-load (Config::from_yaml -> Err), not silently run.
#   valid_form_accepted — a test asserts the legit form still LOADS (the false-reject
#                         guard; round-3 specifically probed for false-positives here).
#
# A cell is EXACTLY one of test:/na:/gap: as in the sibling ledgers. (The related
# invariant "the DERIVED CdcExportConfig::default() is bounded, not a daemon" is a
# Rust-Default correctness property, not a config-load rejection, so it lives in its
# own test cdc_export_config_rust_default_is_bounded_not_a_daemon rather than here.)

engines: [rejected_wrong_mode, valid_form_accepted]

scenarios:
  - id: chunk_column_outside_chunked
    what: "chunk_column set without `mode: chunked` — silently dropped to a single unbounded snapshot before the guard (#14)."
    rejected_wrong_mode: { test: chunk_column_without_chunked_mode_rejected }
    valid_form_accepted: { test: chunk_knobs_accepted_under_chunked_mode }

  - id: nondefault_chunk_size_outside_chunked
    what: "a non-default chunk_size without `mode: chunked` — silently ignored (#14)."
    rejected_wrong_mode: { test: nondefault_chunk_size_without_chunked_mode_rejected }
    valid_form_accepted: { test: chunk_knobs_accepted_under_chunked_mode }

  - id: chunk_size_vs_memory_mb_conflict
    what: "chunk_size + chunk_size_memory_mb both set — documented mutually exclusive; chunk_size was silently dropped for the memory budget (#17)."
    rejected_wrong_mode: { test: chunk_size_and_memory_mb_both_set_rejected }
    valid_form_accepted: { test: chunk_knobs_accepted_under_chunked_mode }

  - id: partition_by_incompatible_mode
    what: "partition_by + mode: cdc — passed `rivet check`, then died at run after a live probe with a misleading 'requires table:' (#15)."
    rejected_wrong_mode: { test: partition_by_with_cdc_mode_rejected_at_load }
    valid_form_accepted: { test: valid_partition_by_and_tables_configs_are_accepted }

  - id: partition_by_missing_token
    what: "partition_by without a {partition} destination token — enforced only in the run pipeline, so `rivet check` gave a false green (#16)."
    rejected_wrong_mode: { test: partition_by_without_token_rejected_at_check_time }
    valid_form_accepted: { test: valid_partition_by_and_tables_configs_are_accepted }

  - id: partition_by_unsafe_column
    what: "partition_by column name that becomes an unsafe Hive col=value path segment (a quoted '../x') — traversal (#6)."
    rejected_wrong_mode: { test: partition_by_column_name_traversal_rejected_at_load }
    valid_form_accepted: { na: "the 'valid' counterpart is a filename-safe column name, exercised by partition_by_incompatible_mode's accept cell (a normal partition_by config loads)" }

  - id: cdc_tables_unsafe_entry
    what: "a CDC tables: entry that becomes a destination path segment — a '..' entry escapes the configured tree (#5)."
    rejected_wrong_mode: { test: cdc_tables_entry_with_traversal_rejected_at_load }
    valid_form_accepted: { test: valid_partition_by_and_tables_configs_are_accepted }

  # ── 0.21.2 dogfood additions ────────────────────────────────────────────────
  - id: partition_by_top_level_load
    what: "partition_by + a TOP-LEVEL load: block — the partition guard fired only for a PER-EXPORT load:, so `rivet check` passed and the warehouse loader would load ONE partition while cleanup_source wiped the rest (dogfood HIGH #101). Rejected at config-load like the per-export form."
    rejected_wrong_mode: { test: top_level_load_with_partition_by_is_rejected }
    valid_form_accepted: { test: valid_partition_by_and_tables_configs_are_accepted }

  - id: max_file_size_nonpositive
    what: "max_file_size 0 / negative (\"0\", \"0B\", \"-5MB\") — the float→u64 cast SATURATED it to a 0-byte rotation threshold (a new part after every row), silently (dogfood LOW). Rejected at parse like a non-numeric value; a positive size (\"1B\") still accepted (the false-reject guard is the accept assert in the same test)."
    rejected_wrong_mode: { test: parse_zero_and_negative_rejected_not_coerced_to_zero }
    valid_form_accepted: { test: parse_zero_and_negative_rejected_not_coerced_to_zero }

  - id: cross_warehouse_load_field
    what: "a load: block carrying a field for a DIFFERENT warehouse (target: snowflake + BigQuery's project:/dataset:) — silently accepted and IGNORED because #[serde(flatten)] on the target enum disables deny_unknown_fields (dogfood LOW; the 'invalid combos fail to deserialize' comment was false). Now a loud reject naming the foreign field + its warehouse; a target-matching block still loads (accept assert in the same test)."
    rejected_wrong_mode: { test: cross_warehouse_load_fields_are_rejected }
    valid_form_accepted: { test: cross_warehouse_load_fields_are_rejected }

  - id: chunked_needs_a_strategy
    what: "chunked mode with NO strategy at all (no chunk_column / chunk_by_key / chunk_count / chunk_by_days and no table:) is rejected at config-load — but chunk_by_key IS a strategy, so chunk_by_key + query: LOADS (the table: requirement is a plan-time concern, with an accurate 'needs table:' message). Fixes the dead-end that recommended chunk_by_key when it was already set (dogfood MED)."
    rejected_wrong_mode: { test: chunk_by_key_with_query_is_not_the_generic_pick_a_strategy_error }
    valid_form_accepted: { test: chunk_by_key_with_query_is_not_the_generic_pick_a_strategy_error }