Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Architecture Decision Records

Each ADR records one decision. Records follow the team house style and round-trip to Confluence via mark. Status flows Draft → For Review → Accepted (or Rejected / Superseded).

The decisions below were developed during design. Records are written per decision, not per crate — most decisions cut across several crates, and several crates carry no decision of their own.

ADRDecisionStatus
0001Pure-Rust, sans-io ecosystem with three co-equal representationsPlanned — stub drafted
0002Neutral value model vs. upstream value typesPlanned
0003Arrow / DataFusion version strategyAccepteddrafted; pin to DataFusion’s Arrow major, no bridge
0004Offset correlation and locator propagation (incl. unnest cardinality)Planned
0005Record metadata as reserved columnsPlanned
0006Connector flow control: state machine + admission controlPlanned
0007Transform DAG, interior sinks, and materialisationPlanned
0008Extension model: in-process WASM vs. Flight sidecarPlanned
0009Primary-raw role, offset colocation, and recovery topologyPlanned
0010Fresh Pulsar client vs. forking an existing cratePlanned
0011Packaging: static musl binary primary, multi-arch OCI derivedPlanned
0012All sources and sinks are optional and modular; replay-capable ones may hold the primary-raw rolePlanned
0013Observability: OTLP default, Prometheus scrape (disableable)Planned
0014Data-quality enforcement: modes and splitPlanned
0015Batch CLI as a bounded source sharing the streaming pipelinePlanned
0016Data contracts: ODCS precedence, quality-rule merge (most-restrictive wins)Planned
0017Unified DLQ with reason-codes (decode / contract / DQ / retry-exhausted)Planned
0018Contract loading: local, HTTP(S), object store (S3/ABFS)Planned
0019Type-mapping authority: describe-only sans-io leaf (type-map)Planned
0020Arrow Flight/IPC as a first-class source and sink transportPlanned
0021Testing standard: per-crate coverage + e2e harness + encoded regressionsPlanned
0022Table-format layer: Parquet, Delta, Iceberg (read+write), Delta Sharing (read)Planned
0023Support one open table format — Iceberg — not two; read Delta via generated Iceberg metadata and the catalog’s Iceberg REST endpointPlanned
0024Catalog credential vending: UC, S3 Tables, S3/IAM, Iceberg RESTPlanned
0025Custom binary decode: batch-oriented WASM default (framing native), native compile-in as measured exceptionPlanned
0026Arrow IPC (non-Flight) file + stream as first-class source/sinkPlanned
0027Avro Object Container Files as a batch source (shared Avro decode)Planned
0028TOML config carried verbatim by K8s (file-mount default, pointer option); no TOML↔YAML conversionPlanned
0029Shared resource loader (local/HTTP/object-store) for config, contracts, and SQLPlanned
0030Secret enumeration tooling (config secrets)Planned
0031Health tree with three projections; readiness gated by source + primary-raw onlyPlanned
0032Unified observability crate (metrics + OTLP + health share one surface)Planned
0033Batch reader libraries: arrow-native + calamine + quick-xml; Polars rejectedPlanned
0034DQ audit trail: full-grain per-record per-rule, first-class sink, on by defaultPlanned
0035Contract schema beats inference across CSV/JSON/XML batch readsPlanned
0036Drop rules: fourth disposition, silent by default (opt-in audit), ODCS+manual mergePlanned
0037Catalog descriptive metadata: comments/properties/tags on create+evolution, idempotent re-syncPlanned
0038Source-ack invariant: advance offset only on durable sink ack; batch-granular default, per-record opt-in; durable mandatory for primary-rawPlanned
0039Live per-stage memory/throughput digest: OTEL gauges + in-process /stats (30s window); honest per-stage attributionPlanned
0040Self-correcting admission control: live measured p95 record size, static config as cold-start seed + floorPlanned
0041Quarantine non-blocking by construction; overflow drops-with-count; recovery rehydrates (skip-DLQ opt-in)Planned
0042Arrow C Data Interface inbound source (trusted in-process zero-copy handoff), filling the extension matrixPlanned
0043Single twg-ffi crate for both FFI directions; sole audited unsafe exceptionPlanned
0044One sink-object-store delegating to format-parquet/delta/iceberg (format by config); plain Parquet raw lane primary-raw-eligiblePlanned
0045Single twg binary with subcommands (stream / batch / config) rather than separate executablesPlanned
0047Independent per-crate publishing under dual MIT OR Apache-2.0; own version, README, testsPlanned
0054Content-hash dedup: opt-in, contract-gated, best-effort, exact membership, batched writes, window sized to upstream retry intervalPlanned
0055Coordination substrate deferred; embedded replicated store the leading shape, platform-independent, consensus library not written in-housePlanned
0056Quorum as an additional worker role with reduced throughput budget; modes 0 / 1 / 3+, two-node forbidden; stable assignment and graceful handoffPlanned
0057Recovery is a precondition for the second sink, not later hardening; only distributed recovery is deferredPlanned
0053Position state may lag, never lead: gap-aware coverage stored with RAW (never in the sink it describes), local write-behind cache, source position only where no broker holds itPlanned
0052Documentation site on Cloudflare Pages at docs.thalweg.dev via Git integration; apex reserved; gates protect the merge, so main must be protectedPlanned
0051Metadata column prefix configurable (default _twg_); changing it on an existing target is a refused migrationPlanned
0050Recovery as a deployment role (ingest / recovery / both); windows leased via the offset store; independent autoscaling to zeroPlanned
0058Record-metadata columns: transport-neutral _twg_source_* superset for broker-supplied fields, bare _twg_* for Thalweg-stamped values (_twg_ingest_ts / _twg_emit_ts / _twg_record_id); amends ADR-0005/0051Draftdrafted
0059Public documentation rendering pipeline: self-hosted rustdoc into docs/site/api/ and mdBook into docs/site/reference/, regenerated locally and committed (Cloudflare build stays NONE); builds on ADR-0052Accepteddrafted
0060Pipelined fire-and-forget sink ack: durable confirmation on a per-stream background lane, advance on the delivered offset, compile-time lane separation; refines ADR-0038’s ack invariant so it doesn’t serialise the sinkDraftdrafted
0061Regenerate the rendered docs (rustdoc + mdBook) on main in CI after each merge and commit them back, instead of in the pre-commit hook; ends the 768-file generated-doc merge conflicts. Amends ADR-0059Accepteddrafted
0062Unity Catalog as a backend module inside twg-table-catalog now, behind the TableCatalog trait; extract to a dedicated twg-catalog-unity client crate only on a stated trigger. Builds on ADR-0024/0037Accepteddrafted
0063Proto-source bundling: twg-proto-bundle (+ twg proto bundle) resolves any proto source (single file / bare dir / src/main/proto repo) to one combined FileDescriptorSet .pb, single + per-package .proto, and a FQ message-type manifest; pure-Rust protox, dedup-by-import-path with identity check, round-trip-gated render. Builds on ADR-0001/0046Draftdrafted
0064Cross-format schema bridge: convert schemas through a neutral hub (twg-contract-core::schema for structure, twg-type-map for leaf types); new twg-schema-bridge crate builds the protobuf → ODCS v3.1.0 spoke (twg proto bundle --emit odcs), packages preserved as ODCS multi-schema references; ODCS→proto + JSON Schema/Avro deferred. Builds on ADR-0016/0019/0063Draftdrafted
0065Zerobus sink build: minimal real substrate (twg-connector-core Sink, twg-stream-arrow BatchSink, twg-offset-store gap-aware union-merge coverage); the SDK inverted behind a ZerobusTransport seam (fake-tested ADR-0060 ack core); Arrow-IPC bytes bridge the 58↔59 major gap so Arrow 59 stays confined to the SDK behind an optional databricks-sdk feature. Builds on ADR-0060/0038/0053/0062/0003Draftdrafted
0049Pulsar flow control: staged subscription, topic-spread shedding, pod-seeded order, pressure-as-scale-signalPlanned
0048Releases via release-plz: reviewed release PR, semver checks, codec version group, Conventional CommitsPlanned
0046Protobuf decode: selectively vendor a zero-copy parser (Apache-2.0), own the registry and Arrow output stageOpen — benchmark

Genuinely open rather than merely undrafted: the protobuf decode strategy (ADR-0046 — direction chosen, licence cleared as Apache-2.0, now gated only on a benchmark against the upstream parser on our hardware and schemas).

Noted for future consideration (not yet scoped)

Captured so they are not lost; no decision or crate yet, and not committed scope:

  • DuckLake as a source and sink — treated like the other database targets (goes through the sink contract / a source adapter, primary-raw eligibility assessed on its durability + replayability like any other).
  • REST and WebSocket (WSS) as a source and a sink — REST polling/webhook and WSS streaming, both directions. WSS-as-source is a streaming transport (fits connector-core); REST-as-source is poll-or-webhook; both as sinks are push/forward targets. Locator/recovery semantics to be worked through when scoped.