Thalweg Plan-vs-Design Reconciliation
Inputs: docs/blueprints/thalweg-delivery-plan.md (v0.5, last-modified 2026-07-24) · docs/adr/README.md (ADRs 0001–0057) · drafted ADR files 0001 (Draft, v0.5) and 0003 (Accepted, v1.0) · crates/ tree (47 crates, all twg- prefixed).
Headline: The plan is one design generation behind. It was written when the whole system was framed as a single ADR (0001) covering ~18 crates; the design has since fragmented into 57 discrete decisions and 47 crates. The plan’s phase spine, layering rules, three-representation model, and fidelity approach remain correct and endorsed. What has drifted is (a) crate naming (unprefixed → twg-), (b) the crate matrix (sinks/sources/formats/contracts/DQ/observability now each have their own crate rather than being folded into a handful), and (c) three named subsystems the plan describes with stale specifics (recovery topology, metadata prefix, observability home). Roughly half the shipped crates have no phase, week budget, or exit gate in the plan at all.
Both ADR files carry an identical import note: “Treat the phase structure and crate layout as current; treat specific version pins and the single-ADR framing as pending update.” That is the reconciliation instruction in miniature — trust the plan’s shape, distrust its specifics.
A. CONFIRMED — plan decisions the ADR set still endorses unchanged
| # | Plan decision | Endorsing ADR(s) | Notes |
|---|---|---|---|
| A1 | Pure-Rust, sans-io ecosystem; three co-equal representations (bytes / neutral value / Arrow) | ADR-0001 (Draft, drafted) | Verbatim match; ADR-0001 §Recommended is Option 3. |
| A2 | Neutral value model owned by codec-core, not upstream re-exports | ADR-0002; ADR-0001 §Recommended | Endorsed. |
| A3 | Arrow default-on; codec-* builds clean --no-default-features with no arrow in tree | ADR-0001 §Recommended; ADR-0003 | Confirmed. |
| A4 | Single Arrow-version chokepoint via twg-codec-core re-export | ADR-0003 (Accepted) | Now settled — see F for the part the plan pre-empts. |
| A5 | Layering enforcement: codec-* may not depend on wire-*/kafka-* or on a runtime; enforced in CI | ADR-0001 §Context/§Recommended | Confirmed; the three CI rules stand. |
| A6 | Offset correlation via sidecar OffsetSpan; unnest cardinality breaks range-correlation and needs per-row locator union | ADR-0004 | Confirmed as a first-class contract. |
| A7 | Record metadata as reserved columns (not out-of-band, which dies at the Flight boundary) | ADR-0005 | Column approach confirmed; prefix value changed — see B2. |
| A8 | Connector flow control: explicit state machine, Budget backpressure, pause/resume, rate limiting | ADR-0006 | Confirmed; extended with admission control (C). |
| A9 | Transform DAG with interior sinks and automatic materialisation of multi-dependent nodes | ADR-0007 | Confirmed. |
| A10 | Two-mechanism extension model: in-process WASM (no network) vs. Flight sidecar | ADR-0008 | Confirmed; C Data Interface inbound added (C). |
| A11 | Fresh Pulsar client, not a pulsar-rs fork | ADR-0010 | Confirmed; flow-control specifics deepened by ADR-0049. |
| A12 | Packaging: static musl binary primary, multi-arch (arm64+amd64) OCI derived | ADR-0011 | Confirmed. |
| A13 | Table catalogs a separate crate from schema registries | ADR-0001 §Recommended; twg-table-catalog | Confirmed. |
| A14 | Passthrough byte-identity asserted post-decompression; recompression not byte-stable | ADR-0001 §Context; ADR-0021 (testing standard) | Confirmed. |
| A15 | Two documented purity exceptions (zstd-encode, GSSAPI) gated off default | ADR-0001 §Recommended | Confirmed. |
| A16 | Source-ack invariant: advance offset only on durable sink ack | ADR-0038 | Confirmed and hardened: batch-granular default, per-record opt-in, durable mandatory for primary-raw. |
B. DEPARTED / SUPERSEDED — plan statements the design has since changed
B1. Recovery / coordination topology (the plan’s single biggest drift)
- Plan says (Phase 5, “Single-agent recovery only”): “One recovery worker needs no leases, no elections and no coordination substrate — it is the only claimant. Distributing recovery across agents is what needs coordination, and that is deferred … (ADR-0055, ADR-0056).” Recovery is framed as an internal capability of the single ingest process, unlocking the second sink.
- Current position — recovery is now a first-class deployment architecture, not an in-process worker:
- ADR-0050: recovery is a deployment role (
ingest/recovery/both); recovery windows are leased via the offset store; roles autoscale independently, to zero. - ADR-0057: reaffirms the plan’s gate (“recovery is a precondition for the second sink, not later hardening”) but narrows the deferral — only distributed recovery is deferred, not recovery itself.
- ADR-0055: coordination substrate deferred, but with a chosen leading shape — an embedded replicated store, platform-independent, consensus library not written in-house.
- ADR-0056: quorum is an additional worker role with a reduced throughput budget; modes 0 / 1 / 3+, two-node forbidden, stable assignment + graceful handoff.
- ADR-0053: the coverage-store mechanics the plan attributes to
twg-offset-storeare now their own decision — position 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 it.
- ADR-0050: recovery is a deployment role (
- Impact: The plan’s ADR citations (0055/0056) are stale numbers pointing at the right idea. The rewrite must (a) split “recovery” into role-based recovery (0050, shippable in Phase 5) vs. distributed/quorum recovery (0055/0056/0057, genuinely deferred), and (b) attribute the coverage-store design to ADR-0053, not fold it into an unspecified
twg-offset-storeparagraph.
B2. Metadata column prefix — __kafka_ → configurable, default _twg_
- Plan says (Record-metadata section, repeatedly): reserved columns under a hard-coded
__kafka_prefix —__kafka_key,__kafka_timestamp,__kafka_offset, etc.; a payload field named__kafka_*is a hard decode error. The quality gate is named “Reserved-namespace collision” against__kafka_*. - Current position — ADR-0051: the metadata column prefix is configurable, default
_twg_; changing it on an existing target is a refused migration. The__kafka_literal is gone (and was transport-specific, which conflicts with the transport-neutral connector goal — Pulsar metadata under a__kafka_prefix is incoherent). - Impact: Every
__kafka_*string in the plan (metadata section, the collision gate, the examples) must become_twg_*(default) with a note that it is configurable and immutable-once-set. This is a pure find-and-replace-plus-semantics change, but it touches a named quality gate.
B3. Observability home — folded into connector-core → unified twg-observability crate
- Plan says (connector layer, Phase 5): “The instrumentation lives in
connector-core, so both transports emit identical metric names.” OTel spans/metrics are aconnector-coreresponsibility; the crate table listsconnector-coredeps astower,opentelemetry,governor. - Current position:
- ADR-0032: a unified observability crate — metrics + OTLP + health share one surface →
twg-observability. - ADR-0013: OTLP default, Prometheus scrape (disableable).
- ADR-0031: health tree with three projections (
/health,/ready,/live); readiness gated by source + primary-raw only. - ADR-0039: live per-stage memory/throughput digest — OTEL gauges + in-process
/stats(30s window), honest per-stage attribution. - Confirmed by crate:
twg-observabilitydesc = “Prometheus metrics, OTEL/OTLP export, and the health tree with /health, /ready, /live projections.”twg-connector-coredesc now reads “…flow control, observability, recovery” — it consumes observability, it no longer owns it.
- ADR-0032: a unified observability crate — metrics + OTLP + health share one surface →
- Impact: The plan must relocate OTel from a
connector-coresub-bullet to a standalone crate + subsystem, and add the health tree and/statsdigest, which have no presence in the plan at all (health/readiness is never mentioned). Cross-transport metric-parity gate stays, but now targetstwg-observability.
B4. Sinks/sources — folded into stream-arrow → a modular source/sink crate matrix
- Plan says (crate table):
stream-arrow= “BatchSinkimplementations, batching policy, IPC, Flight, offset correlation” — i.e. all sink concerns (including Flight and IPC) live in one crate; sources are implicit inkafka-client/pulsar-client. - Current position — sinks and sources are each their own crate, and their existence is a decision (ADR-0012: all sources and sinks are optional and modular; replay-capable ones may hold primary-raw):
- Sinks:
twg-sink-object-store(ADR-0044),twg-sink-flight(ADR-0020),twg-sink-arrow-ipc(ADR-0026),twg-sink-postgres,twg-sink-zerobus. - Sources:
twg-source-flight(ADR-0020),twg-source-arrow-ipc(ADR-0026),twg-source-batch(ADR-0015/0027/0033),twg-source-delta-sharing(ADR-0022). twg-stream-arrowsurvives but is reduced to “batch sinks, IPC, Flight, offset correlation” as a shared substrate the modular sinks build on — not the home of every sink implementation.
- Sinks:
- Impact: The plan’s Phase 5 “
stream-arrow: … all four implementations (RawSink,ValueSink,ArrowSink,TeeSink)” is still valid as the core batching/correlation layer, but the plan has no concept of the 9 modular source/sink crates as separate deliverables. These need phase placement (see C and E).
B5. Single twg binary, not a library-only ecosystem
- Plan implies a library ecosystem plus a “deployable” that appears at the transform layer; there is no CLI/binary crate in the plan’s crate table, and packaging (Phase 9) produces “a binary” without naming its structure.
- Current position — ADR-0045: a single
twgbinary with subcommands (stream/batch/config), not separate executables. Crate:twg-cli. - Impact: The binary is now a named crate with a defined command surface (including a whole batch mode, see C) and needs to appear in the workspace layout and packaging phase.
B6. Batch is now co-equal with streaming (not present in the plan)
- Plan says nothing — it is streaming-only end to end.
- Current position — ADR-0015: a batch CLI as a bounded source sharing the streaming pipeline; ADR-0027 Avro OCF as a batch source (shared Avro decode); ADR-0033 batch reader libraries (arrow-native + calamine + quick-xml; Polars rejected). Crate
twg-source-batchreads Parquet/CSV/JSON/XML/Excel/Avro-OCF. - Impact: This is a departure by omission — the plan asserts a streaming-only scope that the design has widened. See C for scope placement.
C. NEW / ABSENT-FROM-PLAN — subsystems with no phase, week budget, or exit criteria
Each entry: subsystem → ADR(s) → implementing crate(s) → recommended phase.
| # | Subsystem | ADR(s) | Crate(s) | Recommended placement |
|---|---|---|---|---|
| C1 | Data contracts / ODCS — resolved validation spec, ODCS v3.x precedence, most-restrictive merge | 0016, 0018, 0035, 0036 | twg-contract-core, twg-contract-odcs | New sub-phase, sequenced with codecs/DQ. Contract-driven schema (0035) gates codec inference; core belongs alongside Phase 2 codec work, ODCS loader after resource-loader. |
| C2 | Data quality — enforcement modes (strict/quarantine/annotate), clean/reject split, drop rules; full-grain audit trail on by default | 0014, 0034, 0036, 0041 | twg-dq-enforcer, twg-dq-audit | New phase or large Phase 9 attachment. DQ runs inside the transform DAG; audit is a first-class sink. Depends on contracts (C1) + DAG (Phase 9). |
| C3 | Table formats — Parquet, Iceberg (read+write); Delta via Iceberg metadata; Delta Sharing (read); catalog credential vending | 0022, 0023, 0024, 0044 | twg-format-parquet, twg-format-iceberg, twg-source-delta-sharing | New phase (largest absent block). Iceberg-only per ADR-0023. Feeds twg-sink-object-store. Roughly parallels/extends the plan’s Phase 7 “AWS block”. |
| C4 | Batch mode — bounded source over the streaming pipeline; batch readers | 0015, 0027, 0033 | twg-source-batch, twg-cli (batch subcommand) | New phase, post Phase 5 (needs the sink contract + source trait). See B6. |
| C5 | Modular sink crates | 0012, 0044, 0020, 0026 | twg-sink-object-store, twg-sink-flight, twg-sink-arrow-ipc, twg-sink-postgres, twg-sink-zerobus | Attach to Phase 5 (object-store + arrow-ipc + flight are core sink lane) and Phase 7/breadth (postgres, zerobus). object-store Parquet raw lane is primary-raw-eligible (0044) → Phase 5 critical. |
| C6 | Modular source crates | 0012, 0020, 0026, 0022 | twg-source-arrow-ipc, twg-source-flight, twg-source-delta-sharing, twg-source-batch | Phase 5 (Flight/IPC) + new format/batch phases. |
| C7 | Unified observability + health | 0013, 0031, 0032, 0039 | twg-observability | Pull forward into Phase 5 (or a slice into Phase 0/3 for basic metrics). Health tree + readiness gating are wholly absent from the plan. See B3. |
| C8 | FFI / Arrow C Data Interface | 0042, 0043 | twg-ffi | Phase 9 (WASM uses the C Data Interface across its boundary). Sole audited unsafe crate — conflicts with plan’s blanket unsafe_code="forbid" claim (see E, Phase 0). Also the escape-path bridge for ADR-0003. |
| C9 | Type-mapping authority | 0019 | twg-type-map | Phase 1 — sans-io describe-only leaf that codecs and sinks execute against; foundational, belongs with codec-core/value model. |
| C10 | Shared resource loader | 0029 | twg-resource-loader | Phase 1/2 — needed by config, ODCS contracts, and transform SQL. Foundational; pull early. |
| C11 | Config + secrets — layered TOML<env<CLI, K8s file-mount + pointer, secret enumeration; holds admission-control cold-start seed | 0028, 0030 | twg-config | Phase 0/1 — config is needed the moment anything is deployable. Absent from plan. |
| C12 | DLQ reason-codes — unified DLQ (decode / contract / DQ / retry-exhausted) | 0017 | twg-connector-core (+ dq crates) | Phase 5 (plan has “DLQ policy” but no reason-code taxonomy). Quarantine non-blocking + overflow drop-with-count is ADR-0041. |
| C13 | Content-hash dedup | 0054 | twg-connector-core / recovery path | Phase 5 — opt-in, contract-gated, window sized to upstream retry interval. Plan mentions “deduplicated by record id” in recovery but not as a decision. |
| C14 | Admission control — self-correcting, live measured p95 record size; static config as cold-start seed + floor | 0038, 0040 | twg-connector-core, seed in twg-config | Phase 5 — extends Budget flow control. Absent from plan’s flow-control description. |
| C15 | Health tree | 0031 | twg-observability | Phase 5 (with C7). Readiness gated by source + primary-raw only — wholly new. |
| C16 | Releases / publishing — independent per-crate publishing, dual MIT OR Apache-2.0; release-plz reviewed release PR, semver checks, codec version group | 0047, 0048 | workspace-wide (all crates) | Phase 0 (publishing discipline) + ongoing. ADR-0047 makes arrow a public dep — the coupling ADR-0003 turns on. Absent from plan. |
| C17 | Custom binary decode | 0025 | twg-codec-custom | Phase 7/breadth — batch-oriented WASM default, native compile-in as measured exception. Absent from plan’s codec list. |
| C18 | Catalog descriptive metadata — comments/properties/tags on create+evolution, idempotent re-sync | 0037 | twg-table-catalog | Table-format phase (C3). Extends the plan’s Glue “registration” direction. |
| C19 | E2E harness | 0021 | twg-e2e | Phase 0 onward — the plan describes the test tiers but not a dedicated harness crate. |
| C20 | Docs site — Cloudflare Pages at docs.thalweg.dev, gates protect merge, main protected | 0052 | (docs infra) | Phase 0 / infra — out of crate scope but a committed decision the plan omits. |
Codecs not in the plan’s Phase 7 list: twg-codec-custom (C17). Plan’s Phase 7 lists protobuf/json/xml only.
D. CRATE-LEVEL MAP — plan (~18, unprefixed) vs. actual (43, twg-)
Naming drift: The plan uses unprefixed names throughout (wire-tls, codec-core, stream-arrow). Every shipped crate is twg- prefixed. The plan already used the prefix in exactly one place — twg-offset-store in Phase 5 prose — showing the convention post-dates the plan and was applied inconsistently. The rewrite must prefix all 43.
| Actual crate | Status | Plan name / origin | ADR / note |
|---|---|---|---|
twg-wire-tls | in-plan (renamed) | wire-tls | — |
twg-wire-sasl | in-plan (renamed) | wire-sasl | — |
twg-wire-compression | in-plan (renamed) | wire-compression | — |
twg-kafka-client | in-plan (renamed) | kafka-client | — |
twg-pulsar-client | in-plan (renamed) | pulsar-client | ADR-0010/0049 |
twg-connector-core | in-plan (renamed, scope reduced) | connector-core | Observability moved out (B3) |
twg-pipeline-sql | in-plan (renamed) | pipeline-sql | ADR-0007 |
twg-pipeline-wasm | in-plan (renamed) | pipeline-wasm | ADR-0008 |
twg-pipeline-flight | in-plan (renamed) | pipeline-flight | ADR-0008 |
twg-schema-registry | in-plan (renamed) | schema-registry | — |
twg-table-catalog | in-plan (renamed, extended) | table-catalog | +metadata/vending 0024/0037 |
twg-codec-core | in-plan (renamed) | codec-core | ADR-0003 chokepoint |
twg-codec-avro | in-plan (renamed) | codec-avro | — |
twg-codec-protobuf | in-plan (renamed) | codec-protobuf | ADR-0046 open |
twg-codec-json | in-plan (renamed) | codec-json | — |
twg-codec-xml | in-plan (renamed) | codec-xml | — |
twg-stream-arrow | in-plan (renamed, scope reduced) | stream-arrow | Sinks split out (B4) |
twg-kafka-arrow | in-plan (renamed) | kafka-arrow | — |
twg-pulsar-arrow | in-plan (renamed) | pulsar-arrow (mermaid only) | — |
twg-offset-store | in-plan (already prefixed) | twg-offset-store (Phase 5 prose) | ADR-0053 |
twg-cli | NEW | — | ADR-0045/0015 |
twg-codec-custom | NEW | — | ADR-0025 |
twg-config | NEW | — | ADR-0028/0030/0040 |
twg-contract-core | NEW | — | ADR-0016/0036 |
twg-contract-odcs | NEW | — | ADR-0016/0018 |
twg-dq-audit | NEW | — | ADR-0034 |
twg-dq-enforcer | NEW | — | ADR-0014/0036/0041 |
twg-e2e | NEW | — | ADR-0021 |
twg-ffi | NEW | — | ADR-0042/0043 |
twg-format-iceberg | NEW | — | ADR-0022/0023 |
twg-format-parquet | NEW | — | ADR-0022/0044 |
twg-observability | NEW | — | ADR-0013/0031/0032/0039 |
twg-proto-flatten | NEW | — | ADR-0046 |
twg-proto-schema | NEW | — | ADR-0046 |
twg-proto-decode | NEW | — | ADR-0046 |
twg-resource-loader | NEW | — | ADR-0029 |
twg-sink-arrow-ipc | NEW | — | ADR-0026 |
twg-sink-flight | NEW | — | ADR-0020 |
twg-sink-object-store | NEW | — | ADR-0044 |
twg-sink-postgres | NEW | — | ADR-0012 |
twg-sink-zerobus | NEW | — | ADR-0012 |
twg-source-arrow-ipc | NEW | — | ADR-0026 |
twg-source-batch | NEW | — | ADR-0015/0027/0033 |
twg-source-delta-sharing | NEW | — | ADR-0022 |
twg-source-flight | NEW | — | ADR-0020 |
twg-type-map | NEW | — | ADR-0019 |
Totals: 20 in-plan (19 renamed + 1 already-prefixed) · 26 NEW · 46 actual (of 47 workspace crates; this reconciliation table predates and omits twg-udf). The plan accounts for less than half the crate tree.
E. PER-PHASE IMPACT
Phase 0 — Foundations (2w)
- Wrong/incomplete: claims workspace-wide
unsafe_code = "forbid"— contradicted by ADR-0043:twg-ffiis the sole auditedunsafeexception. The rewrite must state “forbid with one crate-level allow, audited.” - Absent scope to attach: publishing discipline (ADR-0047/0048, release-plz, dual-licence, semver checks),
twg-configskeleton,twg-e2eharness scaffolding, docs-site infra (ADR-0052 —mainbranch protection is a gate precondition). - Static-musl/
aws-lc-rsproof stays correct.
Phase 1 — Transport primitives + value model (5w)
- Correct in spine.
- Absent scope:
twg-type-map(ADR-0019) belongs here as a sans-io leaf beside the value model;twg-resource-loader(ADR-0029) foundational, pull in here or Phase 2;twg-config(ADR-0028/0030).
Phase 2 — Avro codec, all three surfaces (6w)
- Correct. Note ADR-0027 (Avro OCF) shares this decode — flag the reuse forward to batch mode.
- Absent scope:
twg-contract-core/twg-contract-odcsfirst landing — contract-beats-inference (ADR-0035) interacts with codec schema resolution and should be designed alongside, not after.
Phase 3 — Kafka consumer, no groups (5w)
- Correct. Passthrough-ships-early claim stands.
- Absent scope: basic
twg-observabilitymetrics slice could start here (plan defers all OTel to Phase 5).
Phase 4 — Consumer groups (8w)
- Correct and unchanged. No drift. Still the hard phase per ADR-0001.
Phase 5 — Sinks, connector layer, coverage & recovery (11w) — most drift
- Wrong: “instrumentation lives in
connector-core” → moved totwg-observability(B3).__kafka_prefix →_twg_(B2). “single-agent recovery only (ADR-0055/0056)” → role-based recovery per ADR-0050/0053/0057, distributed deferred (B1). - Absent scope to attach:
twg-observability+ health tree +/stats(C7/C15); modular sink lanetwg-sink-object-store/-arrow-ipc/-flight+ sourcetwg-source-flight/-arrow-ipc(C5/C6); DLQ reason-codes (C12); admission control (C14); dedup (C13); source-ack invariant hardening (ADR-0038).twg-offset-storemechanics → attribute to ADR-0053. - Resequencing: Phase 5 is already 11 weeks and monolithic; this much added scope likely forces a split into 5a (single-sink + observability + connector-core) and 5b (coverage/recovery/multi-sink + object-store primary-raw lane).
Phase 6 — Producer, idempotence, transactions (6w)
- Correct. No drift.
Phase 7 — Ecosystem breadth (“ongoing”)
- Flagged as requested: Phase 7 is labelled “ongoing” with no exit gate — the only phase without one. This must be closed: either give it explicit exit criteria or split its contents into gated phases. It currently absorbs codecs (protobuf/json/xml), OAUTHBEARER crates, GSSAPI, and the whole AWS/Glue block, which is too much to leave ungated.
- Absent scope:
twg-codec-custom(C17); the modular DB sinkstwg-sink-postgres/twg-sink-zerobus(C5); the table-format block (C3) is far larger than the plan’s “Glue Data Catalog” bullet and probably deserves its own phase, not a Phase 7 sub-item.
Phase 8 — Pulsar (10w)
- Correct. Deepen with ADR-0049 (Pulsar flow control: staged subscription, topic-spread shedding, pod-seeded order, pressure-as-scale-signal) — the plan’s Pulsar gaps list predates this decision.
Phase 9 — Transform layer + packaging (12w)
- Correct in spine.
- Absent scope:
twg-ffi(C8, the WASM C Data Interface boundary + ADR-0003 escape bridge); data-quality enforcement + audit (C2) run inside the DAG and have no home otherwise;twg-clicommand surface + batch subcommand (B5/C4).
Cross-cutting resequencing gaps
- No headcount / parallelism assumption stated. The plan asserts “three critical paths” and “Phase 9 runs parallel to Phase 6 given separate ownership” but never states how many people/streams the timeline assumes. With 23 new crates (contracts, DQ, formats, batch, observability, 9 sink/source crates), the parallelism assumption is now load-bearing and must be made explicit — otherwise the Gantt is unfalsifiable.
- New subsystems have no Gantt bars at all: contracts, DQ, table formats, batch mode, observability/health, and the modular sink/source matrix appear nowhere in the timeline.
F. OPEN / PROVISIONAL — decisions the plan presents as settled but are genuinely open
| # | Item | Status | Plan’s (over-)commitment |
|---|---|---|---|
| F1 | Protobuf decode strategy | ADR-0046 — Open, gated on benchmark (README calls it out explicitly: direction chosen, Apache-2.0 licence cleared, “now gated only on a benchmark against the upstream parser on our hardware and schemas”) | Plan’s Phase 7 lists “Protobuf codec, both surfaces (prost-reflect dynamic …)” as settled work — but the parser choice (vendor a zero-copy parser vs. prost-reflect) is undecided pending benchmark. |
| F2 | Coordination substrate shape | ADR-0055 — deferred; leading shape only (embedded replicated store, consensus library not yet chosen) | Plan cites 0055/0056 as if the deferral is clean; the shape is provisional, not merely deferred. |
| F3 | Arrow version escape-path measurements | ADR-0003 (Accepted) but with deferred measurements — IPC-vs-C-Data-Interface crossing cost and the SQL-vs-projection traffic split are explicitly “no longer gating” but unmeasured; the escape path (Options 2/3/4) is designed but unexercised | Plan (v0.5) predates ADR-0003 entirely and treats “Arrow / DataFusion version strategy” as unstated. The rewrite should record 0003 as Accepted (pin Arrow 58) and carry its escape-path measurements as open follow-ups, not settled. |
| F4 | connector-core traits may prove Kafka-shaped | Plan’s own risk register flags this High; ADR-0006 is still Planned | Legitimately provisional until the Phase 5 Kafka retrofit + paper review against Pulsar’s permit/cursor model. Keep as stated risk, not settled contract. |
| F5 | Pulsar in-place seek feasibility | Plan’s risk register keeps “destroy-and-recreate as documented fallback behind a flag” | Genuinely provisional; correctly hedged in the plan — retain. |
Summary for the rewrite
- Prefix everything
twg-and expand the crate table from ~18 to 43 (§D). - Fix the three named departures verbatim: recovery topology (0050/0053/0055/0056/0057, not “single-agent only 0055/0056”), metadata prefix (
_twg_configurable, not__kafka_), observability home (twg-observability, notconnector-core) (§B1–B3). - Add the absent half of the system: contracts/ODCS, data quality + audit, table formats (Iceberg-only), batch mode, the modular source/sink matrix, unified observability + health, FFI, type-map, resource-loader, config/secrets, admission control, dedup, DLQ reason-codes, releases/publishing, custom-decode (§C) — each needs a phase, budget, and exit gate.
- Close Phase 7’s open-ended “ongoing” with an exit gate, and split the overloaded Phase 5.
- State the parallelism/headcount assumption the timeline silently depends on.
- Record ADR-0003 as Accepted (pin Arrow 58) and keep F1–F5 as explicitly open, not settled.
- Reconcile the
unsafe_code = "forbid"claim with the auditedtwg-ffiexception (ADR-0043).