nerve config validate — CI-ready config bundle validation (7/13) - #210
Open
alex-clickhouse wants to merge 1 commit into
Open
nerve config validate — CI-ready config bundle validation (7/13)#210alex-clickhouse wants to merge 1 commit into
alex-clickhouse wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Pull request overview
Adds CI-friendly configuration bundle validation (nerve config validate) and supporting validation primitives to hard-fail on structurally invalid config bundles (cron schedules, gate specs, wrong-shaped layers, unsafe cwd-resolving paths), while remaining intentionally lenient about unset ${ENV_VAR} secrets unless explicitly requested.
Changes:
- Introduces
validate_config_bundle()with detailed reporting and a newnerve config validateCLI command. - Tightens cron schedule and gate-spec validation (including new interval parsing semantics and gate spec field allowlists via
spec_keys). - Expands test coverage and documentation for validation behavior, strictness flags, and plugin non-execution guarantees.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tests/test_cron_gates.py | Adds regression tests for gate-shape normalization/logging behavior. |
| tests/test_config_validate.py | Adds comprehensive tests for config-bundle validation semantics and CLI behavior. |
| tests/test_config_sources.py | Ensures CLI emits clean errors for config mistakes (including bad backend) while preserving tracebacks for internal defects. |
| nerve/cron/service.py | Splits interval parsing to expose _interval_seconds() for validation without changing daemon fallback behavior. |
| nerve/cron/jobs.py | Prevents accidental normalization of wrong-shaped run_if/skip_when_idle, and logs+ignores invalid shapes instead of raising. |
| nerve/cron/gates.py | Adds spec_keys allowlists and improves build_gate() robustness for non-string/unhashable type. |
| nerve/config_validate.py | New validation module: layer reading, cwd-path footgun checks, cron/gate/schedule validation, and reporting. |
| nerve/cli.py | Adds nerve config validate command and refines “clean error vs traceback” behavior in the CLI group callback. |
| docs/cron.md | Documents schedule fallback vs validation behavior, and clarifies that validation does not execute plugin gates. |
| docs/config.md | Adds a full “Validating Configuration” section including CI guidance and flags. |
| config.example.yaml | Updates cron comments and documents cron.auto_reload example. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
alex-clickhouse
force-pushed
the
config-refactor/07-validate
branch
from
July 28, 2026 12:11
726ca79 to
12c7340
Compare
alex-clickhouse
force-pushed
the
config-refactor/07-validate
branch
from
July 28, 2026 12:36
12c7340 to
8c7a5fd
Compare
alex-clickhouse
force-pushed
the
config-refactor/07-validate
branch
from
July 28, 2026 13:14
8c7a5fd to
e171c79
Compare
alex-clickhouse
force-pushed
the
config-refactor/07-validate
branch
from
July 28, 2026 14:23
e171c79 to
a4016f2
Compare
alex-clickhouse
force-pushed
the
config-refactor/07-validate
branch
from
July 28, 2026 14:54
a4016f2 to
09a9260
Compare
alex-clickhouse
force-pushed
the
config-refactor/07-validate
branch
2 times, most recently
from
July 28, 2026 16:03
b923d11 to
aa8026e
Compare
alex-clickhouse
force-pushed
the
config-refactor/07-validate
branch
2 times, most recently
from
July 28, 2026 18:40
2c7f820 to
ee55d3e
Compare
alex-clickhouse
force-pushed
the
config-refactor/07-validate
branch
from
July 29, 2026 08:29
ee55d3e to
51b1ebb
Compare
alex-clickhouse
force-pushed
the
config-refactor/07-validate
branch
3 times, most recently
from
July 29, 2026 10:31
8947dbc to
e165653
Compare
alex-clickhouse
force-pushed
the
config-refactor/07-validate
branch
from
July 29, 2026 13:28
e165653 to
37d5fa6
Compare
alex-clickhouse
marked this pull request as ready for review
July 29, 2026 15:25
alex-clickhouse
force-pushed
the
config-refactor/07-validate
branch
from
July 30, 2026 08:01
37d5fa6 to
7a5ffb6
Compare
Hard-failing validation over a whole bundle — unknown keys, cron job and gate
parsing, source sanity and ${VAR} resolvability — with a non-zero exit so it
drops straight into a config repo's CI.
Validation reads and parses; it never loads the bundle's own code. Importing a
gate plugin to check it would mean the bundle had already executed by the time we
decided it was unfit, so an unrecognized gate type is reported as unverified
rather than accepted or rejected. Built-in gate specs are built, which is what
type-checking a gate spec means.
Two silent-acceptance gaps are closed. A blank path setting is refused with a
message saying what it would actually do: cron.gate_plugins_dir set to "" is not
"no directory" but the daemon's working directory, every .py in which is imported
and executed at startup and on every cron reload. And a schedule the scheduler
will not run now fails CI — a bad crontab, a string that is neither crontab nor
interval, a zero interval, or a non-string that would raise past every handler
the daemon has. Source schedules were not checked at all and now are, through the
same helper the daemon uses, so the validator and the runtime cannot disagree
about what is valid.
Co-Authored-By: Claude <noreply@anthropic.com>
alex-clickhouse
force-pushed
the
config-refactor/07-validate
branch
from
July 30, 2026 10:06
7a5ffb6 to
51fb706
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
nerve config validatechecks a whole config bundle and exits non-zero on any error, so it drops straight into CI on a config repo. It covers unknown keys, cron job and gate parsing, source sanity,${VAR}resolvability, and schedules the scheduler would not actually run as written.--portable-onlydrops the machine-local layers and judges the tracked layer alone.--strict-keysand--strict-envpromote warnings to errors. It runs even when the config cannot otherwise load, which is the point.Why
Every class of error here was previously found by a daemon at start-up, after the change had already merged and synced — leaving the instance on its old config with a log line nobody was reading. Moving the check before the merge is the whole value.
Schedules are the clearest case. A 5-field crontab the scheduler rejects (
99 * * * *) is refused at run time and logged. A schedule that is neither a crontab nor an interval (hourly,@daily) is never complained about at run time at all — it silently never fires.--portable-onlyexists because a machine-local override can mask an invalid shared value, and, more commonly, a broken local file condemns a shared bundle with nothing wrong with it. Validating the tracked layer on its own is the only question whose answer does not depend on which host ran the check.Validation reads and parses; it does not execute candidate gate-plugin code. "An invalid bundle is refused" is not a guarantee you can make about code you had to run in order to judge it, so an unrecognised gate type is reported as unverified rather than accepted or rejected. Testing a plugin is the author's job.
🤖 Generated with Claude Code