Skip to content

feat(config): a TOML configuration file, for where a person edits it by hand - #3

Merged
wamxx merged 1 commit into
developfrom
feature/toml-config
Aug 29, 2026
Merged

feat(config): a TOML configuration file, for where a person edits it by hand#3
wamxx merged 1 commit into
developfrom
feature/toml-config

Conversation

@wamxx

@wamxx wamxx commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

RESCRIPTUM_CONFIG names a file that sets the same settings under readable names — the prefix gone, tables doing the grouping. It exists for the platform this project was written for: on DSM there is no environment, there is a file, and RESCRIPTUM_ANSWERS_DIR=… on every line is a poor thing to hand somebody editing in File Station.

answers_dir = "/srv/answers"
log         = "problems"

[store]
kind    = "sqlite"
db_path = "/srv/answers.db"

[admin]
addr  = "127.0.0.1:8001"
token = ""

The shape of it

src/tomlconfig.rs maps a document onto the RESCRIPTUM_* names and does nothing else. Every value reaches Config::from_lookup under the key it would have had in the environment, so one place still decides what a setting means and this format cannot grow behaviour the environment lacks — which is what keeps two configuration files from becoming two configurations. A unit test asserts MAPPING covers envfile::KNOWN_KEYS exactly: a setting missing from it is one the file silently cannot configure.

Every rule the env file has carries over unchanged — named and never discovered, the real environment wins, an unreadable named file is a startup error. Naming both files is a transition rather than a steady state, so nothing is refused and the order is said out loud at startup: the environment beats the TOML file, which beats the env file. config set writes the TOML file when both are named, because writing the other would be a change that silently does nothing.

What the implementation settled

  • Replace the value, never the entry. A setting's explanation lives in the key's decor, so inserting over an existing key throws away the paragraph above it — on a packaged install, the only documentation the configuration has.
  • unset empties the value rather than deleting the line, for the same reason. Empty already counts as unset everywhere else here.
  • A configuration file must not live in the answers directory. Every servable .toml at the top of it is an answer document and this format shares the extension, so check reports one dropped there as a misplaced answer. Found by writing the tests; pinned by one rather than left to be discovered.

Cost

A mapping, not a dependency — toml_edit already parses every answer document. Measured on armv7: +14,544 bytes (2,799,168 → 2,813,712), 0.5%.

While measuring, both size tables in the repository turned out to be stale by roughly 200 KB and to disagree with each other. All four feature combinations were re-measured in one sitting and both tables corrected. The boot budget question is now written against 1,164,120 rather than the older figure, and says so.

Tests

613 (+31), including the two that were watched failing before being trusted: the precedence between the two files, and the comments surviving a write.

Not in this PR, deliberately

The DSM package still writes its .env. Switching it means a postupgrade that translates the old file once, and packaging/dsm/CLAUDE.md requires that to be watched running on the machine rather than reasoned about at a desk.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KQnAk5r4fLKcWuAwUY6Pa6

…by hand

`RESCRIPTUM_CONFIG` names a file that sets the same settings under readable
names: the prefix gone, tables doing the grouping (`store.kind`, `admin.token`,
`server.workers`). It exists for the platform the project was written for — on
DSM there is no environment, there is a file, and `RESCRIPTUM_ANSWERS_DIR=…` on
every line is a poor thing to hand somebody editing in File Station.

`src/tomlconfig.rs` maps a document onto the `RESCRIPTUM_*` names and does
nothing else: every value reaches `Config::from_lookup` under the key it would
have had in the environment, so one place still decides what a setting means and
this format cannot grow behaviour the environment lacks. A unit test asserts
`MAPPING` covers `envfile::KNOWN_KEYS` exactly — a setting missing from it is one
the file silently cannot configure.

Every rule the env file has carries over unchanged: named and never discovered,
the real environment wins, and a file that was asked for and cannot be read is a
startup error. Naming both files is a transition rather than a steady state, so
nothing is refused and the order is said out loud: the environment beats the TOML
file, which beats the env file. `config set` writes the TOML file when both are
named, because writing the other would be a change that silently does nothing.

Three things the implementation settled:

- **Replace the value, never the entry.** A setting's explanation lives in the
  *key's* decor, so inserting over an existing key throws away the paragraph
  above it — which on a packaged install is the only documentation the
  configuration has.
- **`unset` empties the value rather than deleting the line**, for the same
  reason. Empty already counts as unset everywhere else in this program.
- **A configuration file must not live in the answers directory.** Every servable
  `.toml` at the top of it is an answer document and this format shares the
  extension, so `check` reports one dropped there as a misplaced answer. Found by
  writing the tests, and pinned by one rather than left to be discovered.

Costs a mapping, not a dependency: `toml_edit` already parses every answer
document. Measured on armv7, +14,544 bytes (2,799,168 → 2,813,712), 0.5%.

While measuring: both size tables in the repository were stale by roughly 200 KB
and disagreed with each other. All four feature combinations re-measured in one
sitting and both tables corrected; the `boot` budget question is now written
against a figure that is 1,164,120 rather than the older one.

Not in this commit, deliberately: the DSM package still writes its `.env`.
Switching it means a `postupgrade` that translates the old file once, and
`packaging/dsm/CLAUDE.md` requires that to be watched running on the machine.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KQnAk5r4fLKcWuAwUY6Pa6
@wamxx
wamxx merged commit e7171ff into develop Aug 29, 2026
6 checks passed
@wamxx
wamxx deleted the feature/toml-config branch August 29, 2026 19:31
wamxx added a commit that referenced this pull request Aug 30, 2026
Since v0.2.0: the whole boot chain and a directory per identity (#2), a TOML
configuration file (#3), and four defects that were live in shipped code — a
rollback blind over the file store, a write that could widen the permissions of
a document holding a root password hash, a log target that stopped every CLI
command for anyone but the service user, and a group `.ipxe` that arms
machines nothing can disarm.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KQnAk5r4fLKcWuAwUY6Pa6
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant