Milestones
List view
Read and write Confluent-framed Avro and JSON Schema through a Confluent-compatible schema registry, both directions, with type tables and a compatibility matrix that state what every conversion does. ## Motivation A customer's topics carry Confluent-framed Avro. Every byte the engine reads is assumed to be JSON, every byte the Kafka sink writes is JSON, and nothing in the config can say otherwise. #272 is the research issue; the design is `docs/superpowers/specs/2026-09-12-schema-registry-mvp-design.md`. ## Decisions - **Avro and JSON Schema only.** Protobuf is a follow-up: decoding needs `protocompile` plus `dynamicpb`, and encoding needs a descriptor synthesized from an Arrow schema. - **The reader schema is the subject's latest version at start**, fixed for the run. A producer that adds a field mid-run surfaces it on the next restart, which is Avro's own resolution behavior. - **The sink has two modes.** With no `schema` block it generates a schema from the SQL output and registers it. With one it fetches the version the config names, registers nothing, and encodes against it. That second mode needs only read-only credentials, which is what a production registry gives a pipeline. - **Five type tables, declared and judged by tests**: Avro to Arrow, Arrow to Avro, JSON Schema to Arrow, Arrow to JSON Schema, and Arrow to JSON. Plus a loop table for a value read and written back in the same format, because DuckDB changes some types on the way through. - **A compatibility matrix.** Writer and reader schema changes on the read side, at unit level. Registry compatibility levels on the write side, measured against Confluent Schema Registry 8.3.1, because the registry's own checker decides those cells. - **A registry failure is not the record's fault.** The error policy guards by domain, so `IGNORE` and `DLQ` never divert a good record over a registry outage. Dead-letter rows carry the record's bytes, its schema id and its position. - **Prior art.** Open-source Apache Flink and Confluent Cloud for Apache Flink were both read on 2026-09-15. The spec's Prior art section records what was copied, what those two disagree on, and where this design departs. ## Scope Each step lands green on its own. The pipeline reads Avro after #300. 1. #296 Config: the blocks, the rules, four error codes. 2. #297 `serde.Registry`: schemas by id and version, reference resolution, caches, metrics. 3. #298 Coverage: the `serde` kind, the input lattices, the compatibility case files. 4. #299 Avro to Arrow, and a two-phase Avro decoder. 5. #300 `TypedBatchHandler`, the `run` wiring, the decoding type runner. 6. #301 The error policy guards by domain, and dead-letter rows keep the record's bytes. 7. #302 JSON Schema to Arrow, its decoder, and the nullable spellings. 8. #303 Compatibility matrix: the read side. 9. #304 Encoders and the Kafka sink: a generated schema, or a registered version. 10. #305 The framed-record producer, the dev stack, the examples and the docs. 11. #306 Integration tests on Kafka and Confluent Schema Registry. 12. #307 Benchmarks, an A/B against `main`, and a soak per format. ## Follow-ups, outside this milestone #308 Protobuf · #309 message keys · #310 the disk and structured handlers · #311 more than one topic · #312 `validate` fetches the schema · #313 AWS Glue · #314 subject naming strategies · #315 the schema GUID in a header · #316 a Kafka passthrough dead-letter queue · #317 writing references · #318 Arrow types for the Avro 1.12 logical types · #319 compatibility columns for other registries.
No due date•0/12 issues closedMake sqlflow a component an organization can adopt: signed, inventoried, versioned, and answerable when a vulnerability lands. ## Motivation sqlflow is a component supplier's product. The system integrator or the OEM certifies the system; sqlflow ships software into it. But nobody deploys an unknown vendor's binary on a plant floor or inside a shipped device without asking a set of questions, and the questions are always the same: who signed this, what is inside it, how long will it be supported, and who do we contact when a CVE lands. None of that requires a certification. All of it requires artifacts, and the artifacts substitute for the reputation a first-time vendor does not have. A disciplined build pipeline emits most of them, so this milestone is cheap relative to what it unblocks: procurement conversations, OEM licensing, and the long-term support commitment that a device vendor with a seven-year field life cannot get from community open source at any price. There is also a deadline. Under the EU Cyber Resilience Act, vulnerability and incident reporting obligations begin **11 September 2026**, with full obligations from 11 December 2027. For open source, commercial activity is determined by whether the software is monetized, so unmonetized MIT sqlflow is likely in the lighter "steward" category — no CE marking, no conformity assessment, but a security policy, cooperation with authorities, reporting of actively exploited vulnerabilities, and accessible remediation. The moment support or an enterprise binary is sold into the EU, that changes. And a commercial vendor distributing open source components inside their product remains responsible for those components, which means sqlflow's answer for DuckDB's CVEs is part of the package, not an upstream problem. ## What the analysis found - **SOC 2 does not apply and should not be pursued.** SOC 2 audits an organization's controls over a service it operates. There is no such thing as a SOC 2 certified binary. Shipping software a customer runs themselves means there is no service in scope and nothing to audit. This is the concrete benefit of the self-hosted model, and it holds until sqlflow operates something on a customer's behalf. - **IEC 62443 is the standard the questions come from.** 62443-4-1 covers the development process, 62443-4-2 the component. Formal certification is not required to get deployed, but the procurement questionnaire maps to it, and answering from a prepared document beats answering from memory in an email thread. - **Support periods are a product, not a policy.** A device vendor shipping hardware with a seven-year field life needs to know someone will patch a CVE in an old minor version years from now. That commitment is impossible to self-serve and costs nothing until it is exercised, which makes it one of the few things a licensee will genuinely pay for. - **1.0 was cut before the failure paths were sound.** A retry defect that drained the buffer and committed shipped under a version number that promises stability. The version policy has to state what a major, minor, and patch actually mean, because the number is currently making a claim the process does not back. - **The pipeline YAML is becoming an API.** The control plane, the dev UI, and any future adapter will all consume it. It has no versioned schema and no compatibility policy. That is cheap to fix now and expensive once three consumers depend on it. ## Decisions - **Artifacts, not certifications.** No SOC 2, no formal 62443 certification, no FIPS validation until a specific deal requires one and pays for it. - **Security artifacts are free.** Signed binaries, SBOMs, the disclosure policy, and CVE advisories ship with the MIT release and are never paywalled. Withholding the means to verify a binary would poison the adoption this whole strategy depends on. The paid surface is the commitment: LTS branches, a response SLA, and indemnity. - **A published security policy before anything is monetized in the EU**, and before the September obligation date regardless. - **The version and support policy is public and specific.** Which versions are supported, for how long, what breaks in a major, and what the config schema compatibility guarantee is. ## Scope 1. `SECURITY.md`: disclosure contact, expected response time, supported versions, coordinated disclosure process. 2. Signed release artifacts and build provenance attestation. 3. SBOM published per release, in a standard format, covering transitive dependencies including DuckDB. 4. Dependency and vulnerability scanning in CI, with a documented triage and advisory process. 5. Versioning policy: the meaning of major, minor, and patch, and the deprecation window. 6. Config schema versioning and a compatibility policy for the pipeline YAML. 7. Support policy: supported versions, support duration, and what an LTS branch would commit to. 8. Platform matrix as a release gate: ARM and x86, container images, and the libc targets edge deployments actually use. 9. Reproducible builds, so a third party can verify the binary matches the source. 10. Release checklist, including a re-run of every tutorial against the released artifact rather than against `main`. 11. A prepared vendor security questionnaire response, mapped to 62443-4-1 and 4-2 sections. 12. CRA steward obligations documented, with a note on what changes if a paid offering ships into the EU. ## Non-goals SOC 2. Formal IEC 62443 certification. FIPS-validated cryptography. Air-gapped licensing. Safety certification of any kind — sqlflow stays out of the control loop, so IEC 61508 and ISO 13849 do not apply and nothing in the roadmap should make them apply. ## Sequencing `SECURITY.md` first and immediately; it is an hour of work and it is the September obligation. Then signing, provenance, and SBOM, which are one pipeline change. Then the versioning and support policy, which is writing rather than engineering but needs a decision about what 1.x now means. Config schema versioning before the control API has consumers. The questionnaire response last, drafted once and reused. ## Open questions - Does selling support into the EU move Turbolytics from steward to manufacturer under CRA, and what does that add? This is a question for a lawyer, not an assumption. - How many LTS branches, and for how long? Every branch is real maintenance, and over-promising here is worse than not offering it. - Is the current 1.x line salvageable, or does the version policy start at the next major with an honest note about what changed? - Should the retry defect get a public advisory? Anyone who ran 1.0.4 through a sink failure may have lost data, and saying so plainly is the same credibility position the benchmark page takes.
No due date•1/1 issues closedOne consumer, many sinks, one commit. Fan out a pipeline to more than one destination without inventing a second delivery guarantee. ## Motivation Every deployment shape that matters needs two outputs, not one. Raw records to cheap local or object storage for replay and investigation, aggregates to the warehouse or the dashboard. Tiered storage at the edge, where raw stays on the gateway and only the rollup crosses a metered link. Store-and-forward, which is fan-out to a durable local sink plus a remote sink that happens to be unreachable. Iceberg, where the archive table and the aggregate table are the same pipeline. sqlflow writes to one sink today. Everything above is currently a second pipeline reading the same topic, which doubles the consumption, splits the offsets, and makes it impossible to say anything true about what landed where. There is a second reason this milestone exists. The retry path that drained the buffer and then committed was a sink-side defect: the pipeline reported healthy, offsets advanced, and rows were gone. Fan-out multiplies the number of ways that ordering can be wrong, so the commit contract has to be stated and tested before there is more than one sink to get wrong. ## What the analysis found - **One offset, one gate.** All sinks flush, all acknowledge, then the offset advances. If any sink fails, nothing commits and the batch replays. Independent offsets per sink are two consumers wearing one coat: divergent progress, no single answer to how far the pipeline has read, and no way to reason about a restart. - **The gate makes every sink at-least-once, and that is fine — but it has to be said.** A replay re-delivers to sinks that already succeeded. For an append-only raw archive, duplicate rows are cheap to filter on read and the trade is worth it. For a sink with a primary key, the duplicate surfaces as a constraint violation, which is a different failure and needs a documented answer. - **Flush cadence differs per sink and the commit is bounded by the slowest.** Raw wants large files, so a long interval. Aggregates flush when the window closes. The effective replay window on a crash is set by whichever sink flushes least often, which means adding a slow sink silently widens the replay window for the fast one. That is a property to expose, not a surprise to discover. - **A failed sink must never release the buffer.** This is the defect that shipped. Buffer ownership has to be explicit: who holds the batch, what releases it, and that the only thing which releases it is a successful flush across every sink. - **Backpressure from one sink stalls the pipeline, and that is correct.** A slow warehouse should slow consumption rather than grow memory without bound. It has to be visible in metrics, because the symptom an operator sees is "the pipeline is behind" with no indication of which sink caused it. - **Permanent failure of one sink is a policy question, not an error.** A warehouse down for six hours should not necessarily stop a gateway from writing its local archive. But continuing means the sinks diverge, and divergence without a loud signal is silent data loss with extra steps. ## Decisions - **A single commit gate across all sinks.** All or nothing, then the offset moves. - **At-least-once, per sink, stated in the docs** with the duplicate behavior spelled out for append-only targets and for keyed targets. - **Durable local staging is a first-class sink type**, not a special case inside store-and-forward. Edge v1 is the policy layer over it. - **No per-sink offsets, no two-phase commit, no exactly-once.** These are non-goals rather than deferred work; the guarantee is the same one the Kafka source already gives. - **Fault injection tests are written with the code, not after it.** Every failure path in this milestone gets a test that fails the sink on the Nth call and asserts what landed in the target, not that the run completed. ## Scope 1. Fan-out: N sinks declared per pipeline, fed from one consumer. 2. Single commit gate: flush all, acknowledge all, then advance the offset. 3. Per-sink flush policy: size, interval, or window close, with the combined replay window derived and exported. 4. Retry semantics: the buffer is retained on failure, retries are bounded, and terminal behavior is defined and loud. 5. Durable local staging sink, sized and bounded, as the substrate for Edge v1. 6. Permanent-failure policy: whether a sink is required or optional, and what happens to the others when a sink is down past its retry budget. 7. Per-sink metrics: rows written, flush latency, failure count, retry count, time since last successful flush. 8. Fault injection harness: fail any sink on demand, assert row counts and absence of gaps in the target. 9. Docs: the delivery guarantee, the duplicate behavior per target type, and the replay-window interaction between sinks. ## Non-goals Exactly-once. Two-phase commit across heterogeneous sinks. Per-sink independent offsets. Adding or removing sinks from a running pipeline. Routing different rows to different sinks by predicate — that is a separate feature and it changes the commit story. ## Sequencing Core Engine v1's state durability and process contract first: the commit gate is the drain path, and a fan-out flush at shutdown is the same code as a fan-out flush mid-stream. Then the commit gate with a single sink, so the contract is proven before the fan-out exists. Then fan-out, retry semantics, and the staging sink, each with its fault-injection test written alongside. Metrics before docs, so the documented behavior is the observed behavior. ## Open questions - Required versus optional sinks: is that per-sink config, or does a pipeline halt whenever any sink is past its retry budget? - Does the staging sink share a DuckDB file with window state, or its own? Separate isolates the write churn and adds a second commit to the gate. - When one sink is keyed and duplicates violate a constraint, is the answer an upsert requirement on that sink type, or a documented constraint that keyed sinks need idempotent writes?
No due dateRun unattended on a gateway with an unreliable, metered uplink: buffer locally when the link is down, forward when it returns, and never lose data to a power cut. ## Motivation The deployment sqlflow is built for is not a datacenter. It is a gateway on a factory floor, a telematics box in a vehicle, a controller in a substation, a server on a vessel. Those machines share a profile: an uplink that is metered, slow, or intermittent; power that is cut without warning; no operator on site; and a visit to fix something that costs a truck roll. Store-and-forward is the feature integrators ask about by name, because it is the one that decides whether data survives the link going down. Ignition sells it as a headline capability and every industrial buyer knows the term. sqlflow does not have it as a stated feature today, and without it the aggregate-before-landing argument does not survive contact with a real site. The substrate is already here. DuckDB implements write-ahead logging and calls `fsync()` explicitly, so a committed transaction survives a crash or power loss, and the DuckDB team verified this by killing the process with `SIGKILL` at random intervals across 4,000 refresh sets, including during WAL recovery, and again on a fault-injecting filesystem. That gives sqlflow a durable local buffer with no new component and a backlog that is queryable in SQL. What is missing is the policy layer on top of it. ## What the analysis found - **Eviction is a correctness decision, not a tuning knob.** A gateway with 8 GB of storage and a three-day outage has to choose: drop oldest, drop newest, or stop consuming and let the source apply backpressure. Each is right for a different customer — a threshold alert wants newest, a compliance record wants oldest — and the choice determines which data exists. It is declared in config, defaulted explicitly, and reported in metrics, never decided implicitly by whatever the buffer does when it fills. - **Drain is not "send everything as fast as possible."** When the link returns there is a backlog plus live data. Draining flat out saturates the link the deployment was protecting and can trip the downstream's rate limits. The drain needs a rate, and a decision about whether live data waits behind the backlog or interleaves with it. - **DuckDB is not a queue.** Single writer, columnar, and deletes are not cheap. Store-and-forward is high-frequency churn of small inserts and deletes, which is close to the anti-pattern for an OLAP store. It will work; the shape has to be measured under a multi-day backlog rather than assumed. - **`fsync` is a promise the hardware can break.** Industrial gateways run on SD and eMMC, where a flush can return before the device has written to NAND. Nothing in sqlflow can fix that, but the durability claim in the docs is scoped to it rather than stated flat. - **Flash write endurance is a field failure mode.** Continuous small writes wear out the card, and the failure appears eighteen months into a deployment at a customer site. Write amplification per unit of buffered data is measured before any claim about months of buffering. - **Enrichment breaks at the edge in ways it does not in a datacenter.** A reference table loaded from S3 or an API at startup cannot load when the gateway boots with the uplink down — which is exactly the scenario store-and-forward exists for. The registry needs a local cached copy with a documented staleness policy, and a refresh path that does not require a restart, because a restart at a remote site is a truck roll. - **Reference tables compete with window state.** A 500k-row asset registry shares DuckDB's memory budget with the open windows. It counts against `max_memory` and it is visible in the density measurements, not invisible beside them. ## Decisions - **Store-and-forward is core and MIT.** It changes what lands, so it sits in the data path. A free version that cannot be trusted with data on an unreliable link is not evaluable, and this is the feature an integrator checks first. - **The staging tier is a sink, not a special case.** Store-and-forward is fan-out to a durable local sink plus a remote sink where the remote one is unavailable. That machinery is Sinks v1; this milestone is the policy that governs it. - **Every policy has an explicit default and a metric.** Buffer depth, oldest un-forwarded record age, eviction count by reason, and drain rate are all exported. An operator who cannot reach the box has to be able to see it from the aggregate stream. - **"Store-and-forward" is the term used in issues, docs, and the site.** It is the phrase integrators search for and recognize. "Buffering" is the same feature that nobody finds. ## Scope 1. Bounded local buffer with a declared size limit, backed by the durable state path. 2. Eviction policy: drop oldest, drop newest, or backpressure. Declared, defaulted, and reported. 3. Drain on reconnect: rate limit, and a defined ordering between backlog and live data. 4. Metered publish: a ceiling on outbound rate independent of drain, for links billed by volume. 5. Buffer observability: depth, age of oldest record, eviction counts by reason, drain state. 6. Reference table refresh without restart. 7. Reference table local cache and a documented staleness policy, so a pipeline starts with the uplink down. 8. Reference table memory accounted against `max_memory` and included in density numbers. 9. Measurement: write amplification per buffered record, and buffer behavior under a multi-day backlog. 10. ARM and x86 release builds, and an idle footprint number on gateway-class hardware. 11. Docs: the durability claim scoped to the hardware, the eviction policies with the case for each, and sizing guidance. ## Non-goals An embedded broker or a general-purpose queue. Exactly-once across a reconnect. Remote fleet management, which is a separate service that talks to this one over the control API. Bidirectional command and control back to devices. ## Sequencing Core Engine v1's durability and process contract first, since the buffer is the state path and the drain is the shutdown path. Sinks v1 next, because store-and-forward is fan-out with one sink unavailable. Then buffer, eviction, drain, metered publish, in that order, each with its metric. Enrichment items run in parallel; they share nothing with the buffer work. Measurement before the docs, so the claims are scoped to a number. ## Open questions - Backpressure or shed as the default? Backpressure is safer for correctness and worse for a source that cannot be paused. - Does the buffer live in the same DuckDB file as window state, or a separate one? Separate isolates the churn but adds a second commit. - Is a multi-day backlog a realistic requirement, or does every real deployment cap at hours? This changes the storage sizing story and it is a question for an integrator, not an assumption.
No due dateConnect sqlflow to the IoT world: subscribe to an MQTT broker as a source, and publish back to one as a sink. ## Motivation MQTT is the transport for device and industrial telemetry: factory lines, smart meters and inverters, fleet telematics, building sensors, EV chargers, and remote sites with intermittent links. That data is born on a gateway at the edge, and the valuable work is reducing it before it travels: per-device tumbling windows, downsampling before the lake, threshold alerts, and enrichment against an asset registry. sqlflow already does that work in SQL, from one binary, in a quarter of a gigabyte, which is the footprint an edge gateway has. What it cannot do is read MQTT. Every MQTT deployment today needs a broker-to-Kafka bridge in front of sqlflow, and the bridge is the piece an industrial buyer does not want to operate. The demand is already in the tracker: #125 (source), #118 (a user asking for source and sink), and the same shape of ask in #139 and #62. ## What the analysis found - **sqlflow is a client, not a broker.** Devices publish to the broker. sqlflow subscribes. It never accepts MQTT connections itself, and it should not: the broker owns auth, fan-out, retained messages, and queuing for offline subscribers. - **Delivery is QoS 1, a persistent session, and an ack only after the batch has flushed to the sink.** That is at-least-once, the same guarantee the Kafka source gives by committing offsets after flush. - **The inflight window bounds the batch.** Unacked QoS 1 messages count against the broker's inflight cap, commonly 20 to 100 and often not tunable. Holding acks for a 5,000-message batch stalls at the cap. Either the batch is clamped to the window or acks advance to a high-water mark. #200 measures which, before #193 commits to one. - **MQTT has no offsets.** Acks go to the broker and window state goes to DuckDB, and the two cannot commit atomically. A crash between them replays a batch into windows that already counted it. The websocket source has the same gap. Document it rather than hide it. - **Retained messages arrive on every subscribe.** The broker delivers the retained value for every matching topic at connect, each with an old timestamp: a burst of very late data at every restart. 3.1.1 cannot suppress it, so the source needs a policy. #201. - **Per-device windows are keyed state proportional to device count.** Tumbling windows evict themselves when they close, so the state is the open windows across every device seen, which is bounded by device cardinality, not by time. That is the bounded-state and eviction item in Core Engine v1 (#162). The tutorial does not claim per-device windows until that policy is documented. - **Scale-out over shared subscriptions does not transfer.** Shared subscriptions round-robin messages with no key affinity, so a keyed window split across nodes counts wrong on every node. The guardrail is "no shared subscriptions under keyed windows," not "one instance": N instances on disjoint topic filters, one per site or per line, is a legitimate edge fleet pattern. Refinement recorded on #171. - **Payloads are JSON first.** Sparkplug B is an open Eclipse and ISO/IEC 20237 specification, but its DATA messages carry metric aliases declared in earlier BIRTH messages, so decoding is stateful per edge node. That is a separate piece, held until a customer asks, and used in conversations now because it is the ask nothing in the lightweight tier can answer. - **The source contract is four methods:** Start, Stream, Commit, Close. The websocket source, about 230 lines, is the template. The Paho Go client provides connect, subscribe, reconnect, and manual acknowledgement. ## Decisions - **MQTT 3.1.1 only.** Shared subscriptions are a non-goal, session expiry is not needed for v1, Sparkplug is built on 3.1.1, and every industrial broker speaks it. Paho's v5 support is a separate client, so the client type stays out of the source interface and v5 stays cheap to add later. - **A source metadata convention, not one-off columns.** MQTT wants topic, QoS, and the retained flag. Sparkplug will want edge node and device id. Kafka has topic, partition, and offset. #194 establishes one convention with the source name in it, and keeps `kafka_topic` as a deprecated alias. - **Ack strategy is decided by measurement.** #200, then #193. ## Scope 1. #200 Spike: inflight limits versus ack-after-flush. First. 2. #197 A broker in the dev stack and a release test. 3. #192 Source: connect, subscribe with wildcards, stream, TLS and auth. 4. #193 Source: ack after flush, persistent session, drain to the #161 process contract. 5. #201 Source: retained-message policy on subscribe. 6. #194 Source metadata convention, with the topic, QoS, and retained flag queryable. 7. #195 Sink: publish rows to a topic with QoS and retain. 8. #196 Sink: per-row topic from a column. 9. #198 Tutorial: device telemetry to Postgres. After #162 documents the eviction policy. 10. #199 Sparkplug B decode. Last, gated on a customer. ## Non-goals An embedded broker. MQTT 5. Shared subscriptions. Exactly-once. Sparkplug before a customer asks for it. ## Sequencing The spike first, since it constrains batch sizing everywhere else. Then the broker in the dev stack. Start the source after #161 lands so it is built to the drain contract rather than retrofitted. Source before sink. The tutorial waits for #162's documented policy. Sparkplug last.
No due date•0/12 issues closedCan one pipeline span nodes? Stateless scale-out over consumer groups, with the guardrails that keep keyed pipelines correct.
No due date•0/4 issues closedCan something else start, stop, and inspect a pipeline? The pipeline CRD, the operator, and the design-time endpoints.
No due date•0/6 issues closedMake a sqlflow process a well-behaved tenant that an external supervisor can run at density. sqlflow does not own scheduling, placement, or coordination. Providers already run an orchestrator, and consumer groups already handle partition assignment and failover. This milestone hardens the single process instead: one pipeline per process, isolation from the OS, density measured before it is optimized. Scope: 1. State durability and recovery. Landed in #158; corrupt-checkpoint detection is the remainder. 2. Lifecycle and process contract. Signal handling, graceful drain, drain deadline, health endpoint, documented exit codes, crash-loop safety. 3. Isolation and resource limits. Declared and enforced max_memory and max_state_size, defined behavior at the limit, bounded eviction, per-batch query timeout, and a security spike on DuckDB running untrusted SQL in-process. 4. Error taxonomy. Two top-level classes, stable machine-readable codes treated as public API, position information on user errors. 5. Bad record handling. A poison record must never crash-loop a pipeline forever. 6. Observability. Tenant ID and pipeline ID as labels on every metric and log line. 7. Metering. Billing counters that survive restart without double-counting. 8. Validation and preview. validate, infer, and preview, plus a local dev UI over the three. 9. Restart-on-edit semantics. What happens to window state and offsets when a definition changes. 10. Density measurements. Idle footprint, cold start, multi-hour soak, throughput per core, x86 and Graviton. Non-goals: distributed coordination, a rebalancing protocol, placement or scheduling, a hosted control plane. Sequencing: state durability, then density measurements, then error taxonomy and observability, then validation and preview. Metering and the dev UI last. The measurements are cheap and unblock the provider conversation, so they do not wait behind the engineering. Open questions: - Fail or shed at the memory limit? - Is untrusted multi-tenant SQL supportable in-process at all, or is process isolation plus a locked-down DuckDB config enough? - Does a real provider conversation validate this before the work starts?
No due date•16/28 issues closed