PATTERN Cited by 1 source
Contract-driven topic provisioning¶
Pattern¶
Make the per-node contract.yaml the single source of truth for
which topics exist on the broker, validated by regex + enum, and
materialised by a single extractor that runs in CI, runtime boot,
and post-boot validation.
The pattern eliminates silent wiring failures from topic-name drift across independently- developed agents in a multi-repo Kafka-shaped system. The ingredients:
- Per-node contract — every node ships a
contract.yamldeclaringsubscribe_topics:andpublish_topics:. See concepts/contract-yaml-as-bus-surface. - Regex + enum validation — topic names follow
onex.{kind}.{producer}.{event}.v{N}, validated by a regex for syntax and aStrEnumfor canonical-name membership. See concepts/regex-plus-enum-validation. - No second copy — "there is no second operator-maintained registry, separate constant list hidden inside the runtime, or manually synchronized provisioning config."
- Single extractor, multi-call-site — see patterns/single-extractor-multi-call-site for the topology.
- Narrow-scope provisioner — creates missing topics only, does not reconcile partition counts / replication / retention.
Disclosed instantiation¶
OmniNode's ContractTopicExtractor "discovers approved packages,
loads each contract.yaml, and returns the union of declared
topics." The extractor runs in three independent places:
new_topic = NewTopic(
name=spec.suffix,
num_partitions=partitions,
replication_factor=spec.replication_factor,
)
await admin.create_topics([new_topic])
Provisioning is "async, best-effort, and non-blocking." If a topic exists, the provisioner "leaves it alone." See the contract.yaml shape:
event_bus:
subscribe_topics:
- "onex.cmd.router.route-request.v1"
- "onex.evt.router.scoring-decision.v1"
publish_topics:
- "onex.evt.router.routing-complete.v1"
- "onex.evt.router.routing-failed.v1"
Why this works¶
Three properties interact:
- Single source of truth eliminates drift — there is exactly one reviewed location where each topic name lives. Drift requires two copies; the pattern removes the second copy.
- Mechanical validation eliminates typo-as-silent-failure — regex + enum reject typo'd names at PR review, runtime boot, and post-boot validation. The bug class never reaches the broker.
- Topology eliminates "works locally, breaks in prod" asymmetry — the same extractor runs in CI and runtime, so "a topic name can only be wrong in the contract."
When to use it¶
The pattern's value is proportional to:
- Number of topics — scale of bug surface. The OmniNode disclosure names "around the fiftieth topic" as the crossing point at which constants-near-publishers stops working.
- Repository fan-out — single-developer-per-topic ownership doesn't need this discipline; cross-repo topic sharing does.
- Refactor frequency — refactors are the primary source of "old topics left behind" drift; the pattern catches it mechanically.
- Cost of silent failure — agent coordination is the OmniNode case; payment processing or healthcare workflows are higher- cost variants.
When the pattern is overkill¶
- Single-repo / single-developer ownership — the constant-near- publisher style is simpler and the drift risk is low.
- <20 topics — the policing overhead of contract.yaml + regex
- enum + extractor doesn't pay back at small scale.
- Hard-coded topic-name choice already enforced by code review conventions — if your team is already disciplined and the topic count is bounded, the contract layer is ceremony.
What it doesn't address¶
- Partition-count drift — provisioner creates with the contract's partition count, but doesn't notice if the contract later requests more.
- Replication-factor drift — same.
- Retention-policy drift — same.
- Schema drift — payload shape is a separate problem; pair with a schema registry (see concepts/schema-registry).
- Producer/consumer offset drift — consumer-group lag is a separate observability problem.
The post is candid: "That boundary is intentional. Creation is contract-owned; reconciliation is a different problem." The disclosed future-work shape: "diff against the contract spec, decide which mismatches are auto-correctable, surface the rest as explicit drift."
Sibling patterns¶
- patterns/single-extractor-multi-call-site — the topology that enforces this pattern.
- patterns/runtime-governance-enforcement-layer — Databricks Lakebase's runtime-policy-enforcement pattern; contract-driven topic provisioning is a streaming-broker variant of the same shape.
- concepts/runtime-api-vs-gitops-source-of-truth — Redpanda Connect's GitOps framing of declarative-source-in- version-control as the source of truth, runtime mutations as not. OmniNode's contract.yaml is the agent-bus equivalent.
Seen in¶
- sources/2026-06-02-redpanda-how-omninode-uses-redpanda-to-scale-ai-agent-workflows (2026-06-02, Redpanda Blog guest post by OmniNode founder Jonah Gray) — canonical wiki instance of this pattern. Provides the contract-yaml shape, regex+enum validation, three-call-site extractor topology (CI / runtime boot / post-boot validation), the narrow-scope creation-only provisioner with explicit no- reconciliation boundary, and the bug class (concepts/silent-wiring-failure) the pattern was built to eliminate. "The contract becomes the only reviewed location where wire-format topic names live. There is no second operator-maintained registry, separate constant list hidden inside the runtime, or manually synchronized provisioning config." Disclosed scale: 12 repositories, 100+ event types.
Related¶
- concepts/contract-yaml-as-bus-surface — the manifest the pattern reads from.
- concepts/regex-plus-enum-validation — the validation layer.
- concepts/topic-name-as-coordination-surface — the architectural condition.
- concepts/silent-wiring-failure — the bug class.
- patterns/single-extractor-multi-call-site — the topology.
- systems/omninode — the canonical wiki adopter.
- systems/redpanda — substrate broker.