keel.toml belongs to the binary, not the library #133

Open
opened 2026-07-29 06:12:59 +00:00 by perishadmin · 0 comments
Contributor

keel::config::load(".") gives the library ownership of a configuration file. That is the wrong side of the boundary.

The defect

A .toml belongs to a binary. When keel is consumed as a library, every runtime value it needs — listen address, store, cache, estate policy — must be supplied by the caller, because the caller is the one that owns a configuration surface and answers to its users for it.

Today a consumer inherits keel.toml whether it wants it or not. For stim that means two configuration files whose [listen] and [store] sections directly overlap, which violates the substrate law that runtime policy enters through exactly one cascade.

What is and is not the problem

The types are fine and should stay: Listen, Cache, Estate, Generation, Cleanup are keel vocabulary, declared by keel, and a caller needs them to express intent. Keeping them is correct — it is the same reason plumb was stripped of Listen/Store/Kind: vocabulary belongs to the layer that owns the meaning.

The problem is narrower: file loading lives in the library. keel-api is a demo binary and may keep keel.toml; keel the library should accept constructed values and never read a file on its own.

Expected shape

  • keel (lib): accepts caller-constructed config values; no file discovery, no load()
  • keel-api (bin): keeps keel.toml and constructs those values from it
  • a consumer such as stim declares its own single config surface and builds keel values from it

Acceptance

  • a library consumer can bind a graph without any keel.toml existing anywhere
  • keel-api behavior is unchanged
  • the repo-rooted discovery path disappears from the library crate
`keel::config::load(".")` gives the **library** ownership of a configuration file. That is the wrong side of the boundary. ## The defect A `.toml` belongs to a binary. When keel is consumed as a library, every runtime value it needs — listen address, store, cache, estate policy — must be supplied by the caller, because the caller is the one that owns a configuration surface and answers to its users for it. Today a consumer inherits `keel.toml` whether it wants it or not. For stim that means two configuration files whose `[listen]` and `[store]` sections directly overlap, which violates the substrate law that runtime policy enters through exactly one cascade. ## What is and is not the problem The **types** are fine and should stay: `Listen`, `Cache`, `Estate`, `Generation`, `Cleanup` are keel vocabulary, declared by keel, and a caller needs them to express intent. Keeping them is correct — it is the same reason plumb was stripped of `Listen`/`Store`/`Kind`: vocabulary belongs to the layer that owns the meaning. The problem is narrower: **file loading lives in the library**. `keel-api` is a demo binary and may keep `keel.toml`; `keel` the library should accept constructed values and never read a file on its own. ## Expected shape - `keel` (lib): accepts caller-constructed config values; no file discovery, no `load()` - `keel-api` (bin): keeps `keel.toml` and constructs those values from it - a consumer such as stim declares its own single config surface and builds keel values from it ## Acceptance - a library consumer can bind a graph without any `keel.toml` existing anywhere - keel-api behavior is unchanged - the repo-rooted discovery path disappears from the library crate
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
PerishLab/keel#133
No description provided.