<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="atom.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://ethanhann.com/confval/releases</id>
    <title>confval Blog</title>
    <updated>2026-07-22T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://ethanhann.com/confval/releases"/>
    <subtitle>confval Blog</subtitle>
    <icon>https://ethanhann.com/confval/img/logo.svg</icon>
    <entry>
        <title type="html"><![CDATA[confval v0.5.0]]></title>
        <id>https://ethanhann.com/confval/releases/v0.5.0</id>
        <link href="https://ethanhann.com/confval/releases/v0.5.0"/>
        <updated>2026-07-22T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Enforce nested spec validation traversal.]]></summary>
        <content type="html"><![CDATA[<p>This release adds a way to automatically ensure all nested specs are validated.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="highlights">Highlights<a href="https://ethanhann.com/confval/releases/v0.5.0#highlights" class="hash-link" aria-label="Direct link to Highlights" title="Direct link to Highlights" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="one-call-validates-the-whole-spec-tree">One call validates the whole spec tree<a href="https://ethanhann.com/confval/releases/v0.5.0#one-call-validates-the-whole-spec-tree" class="hash-link" aria-label="Direct link to One call validates the whole spec tree" title="Direct link to One call validates the whole spec tree" translate="no">​</a></h3>
<p><code>Validate</code> gains a <code>validate_all</code> method that runs a spec type's own rules and then descends into every
<code>#[confval(nested)]</code> field, recursively.</p>
<p>A <code>Validate</code> impl covers one spec type's own fields, so reaching a nested block used to mean calling into it manually
from the parent spec's <code>Validate</code> impl.
Forgetting that call left the nested block unvalidated with nothing to indicate it.</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#654735;--prism-background-color:#f9f5d7"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#654735;background-color:#f9f5d7"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#654735"><span class="token plain">spec</span><span class="token punctuation">.</span><span class="token function" style="color:#72761e">validate_all</span><span class="token punctuation">(</span><span class="token operator" style="color:#a89984">&amp;</span><span class="token keyword" style="color:#af2528">mut</span><span class="token plain"> report</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></div></code></pre></div></div>
<p>The descent comes from <code>#[derive(Spec)]</code>, so a nested block added later is validated without editing a validator.
See <a class="" href="https://ethanhann.com/confval/docs/guide/validation">Validation</a> for the full picture.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="existing-validate-impls-do-not-change">Existing <code>Validate</code> impls do not change<a href="https://ethanhann.com/confval/releases/v0.5.0#existing-validate-impls-do-not-change" class="hash-link" aria-label="Direct link to existing-validate-impls-do-not-change" title="Direct link to existing-validate-impls-do-not-change" translate="no">​</a></h3>
<p><code>Validate::validate</code> keeps its signature and stays the only method you have to write.
<code>validate_all</code> and <code>descend</code> are provided methods, so an impl written against v0.4.0 compiles unchanged.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="added">Added<a href="https://ethanhann.com/confval/releases/v0.5.0#added" class="hash-link" aria-label="Direct link to Added" title="Direct link to Added" translate="no">​</a></h2>
<ul>
<li class=""><code>Validate::validate_all</code>, the entry point that runs a spec's rules and then its nested children.</li>
<li class=""><code>Validate::descend</code>, which decides whether the children of a block are visited.</li>
<li class=""><code>ValidateNested</code>, the traversal trait that <code>#[derive(Spec)]</code> implements for you.</li>
<li class=""><code>ControlFlow</code> and <code>ValidateNested</code> in the prelude.</li>
<li class="">A <code>validate_traversal</code> example.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="changed">Changed<a href="https://ethanhann.com/confval/releases/v0.5.0#changed" class="hash-link" aria-label="Direct link to Changed" title="Direct link to Changed" translate="no">​</a></h2>
<ul>
<li class=""><code>#[derive(Spec)]</code> now emits an <code>impl ValidateNested</code> alongside the <code>impl FromFields</code>.
Nothing about the parser changed.</li>
<li class="">The bound on every generated <code>Lower</code> impl moves from <code>where S: Validate</code> to <code>where S: Validate + ValidateNested</code>.
A spec that derives <code>Spec</code> satisfies the second half automatically.</li>
<li class="">A nested spec without a <code>Validate</code> impl is now a compile error at its parent rather than a block that is skipped.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="upgrading">Upgrading<a href="https://ethanhann.com/confval/releases/v0.5.0#upgrading" class="hash-link" aria-label="Direct link to Upgrading" title="Direct link to Upgrading" translate="no">​</a></h2>
<p>Replace the top level <code>spec.validate(&amp;mut report)</code> with <code>spec.validate_all(&amp;mut report)</code>.</p>
<p>Delete any calls into child specs from your <code>Validate</code> impls.</p>
<p>A leftover call reports the child's issues twice, so it is worth a grep to find the calls and remove them:</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#654735;--prism-background-color:#f9f5d7"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#654735;background-color:#f9f5d7"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#654735"><span class="token plain">grep -rn ".validate(" crates/ </span><br></div></code></pre></div></div>
<p>A spec with a handwritten <code>FromFields</code> has no derive to generate its traversal and needs its own <code>impl ValidateNested</code>.
The lowering bound reports the missing impl.</p>
<div class="language-toml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#654735;--prism-background-color:#f9f5d7"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-toml codeBlock_bY9V thin-scrollbar" style="color:#654735;background-color:#f9f5d7"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#654735"><span class="token plain">[dependencies]</span><br></div><div class="token-line" style="color:#654735"><span class="token plain">confval = { version = "0.5", features = ["derive", "hcl", "color"] }</span><br></div></code></pre></div></div>]]></content>
        <author>
            <name>Ethan Hann</name>
            <uri>https://ethanhann.com</uri>
        </author>
        <category label="release" term="release"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[confval v0.4.0]]></title>
        <id>https://ethanhann.com/confval/releases/v0.4.0</id>
        <link href="https://ethanhann.com/confval/releases/v0.4.0"/>
        <updated>2026-07-19T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[First release on unified workspace versioning.]]></summary>
        <content type="html"><![CDATA[<p>The <code>confval</code> and <code>confval-derive</code> crates now share a single version and are released together.
From this release on, one version number and one set of release notes cover the whole workspace.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="highlights">Highlights<a href="https://ethanhann.com/confval/releases/v0.4.0#highlights" class="hash-link" aria-label="Direct link to Highlights" title="Direct link to Highlights" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="enforced-validate-bound-on-specs">Enforced <code>Validate</code> bound on specs<a href="https://ethanhann.com/confval/releases/v0.4.0#enforced-validate-bound-on-specs" class="hash-link" aria-label="Direct link to enforced-validate-bound-on-specs" title="Direct link to enforced-validate-bound-on-specs" translate="no">​</a></h3>
<p>A compiler error will occur if a spec does not implement the <code>Validate</code> trait.
The trigger for this is lowering.</p>
<p>The compilation error will be similar to this, where the trait is not implemented for the example <code>LimitsSpec</code>.
It materializes as an <code>unsatisfied trait bound</code> on <code>#[derive(confval::Config)]</code>:</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#654735;--prism-background-color:#f9f5d7"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#654735;background-color:#f9f5d7"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#654735"><span class="token plain">error[E0277]: the trait bound `spec::LimitsSpec: confval::pipeline::Validate` is not satisfied</span><br></div><div class="token-line" style="color:#654735"><span class="token plain">  --&gt; crates/confval/examples/common/config.rs:21:10</span><br></div><div class="token-line" style="color:#654735"><span class="token plain">   |</span><br></div><div class="token-line" style="color:#654735"><span class="token plain">21 | #[derive(confval::Config)]</span><br></div><div class="token-line" style="color:#654735"><span class="token plain">   |          ^^^^^^^^^^^^^^^ unsatisfied trait bound</span><br></div><div class="token-line" style="color:#654735"><span class="token plain">   |</span><br></div><div class="token-line" style="color:#654735"><span class="token plain">help: the trait `confval::pipeline::Validate` is not implemented for `spec::LimitsSpec`</span><br></div><div class="token-line" style="color:#654735"><span class="token plain">  --&gt; crates/confval/examples/common/spec.rs:23:1</span><br></div></code></pre></div></div>
<p>To resolve such errors, implement the trait for the spec.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="unified-workspace-versioning">Unified workspace versioning<a href="https://ethanhann.com/confval/releases/v0.4.0#unified-workspace-versioning" class="hash-link" aria-label="Direct link to Unified workspace versioning" title="Direct link to Unified workspace versioning" translate="no">​</a></h3>
<p><code>confval</code> and <code>confval-derive</code> are now versioned in lockstep through <code>[workspace.package]</code>.</p>
<p><code>confval</code> pins its derive crate with <code>confval-derive = "=0.4.0"</code>, so a given <code>confval</code> always resolves the matching
derive.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="changed">Changed<a href="https://ethanhann.com/confval/releases/v0.4.0#changed" class="hash-link" aria-label="Direct link to Changed" title="Direct link to Changed" translate="no">​</a></h2>
<ul>
<li class=""><code>confval-derive</code> moves from <code>0.1.1</code> to <code>0.4.0</code> to align with <code>confval</code>.
This is a version-number change only.
There is no change to the derive macro output or its public API.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="upgrading">Upgrading<a href="https://ethanhann.com/confval/releases/v0.4.0#upgrading" class="hash-link" aria-label="Direct link to Upgrading" title="Direct link to Upgrading" translate="no">​</a></h2>
<p>Depend on <code>confval</code> as before.
The <code>derive</code> feature continues to pull in the matching <code>confval-derive</code> automatically.</p>
<div class="language-toml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#654735;--prism-background-color:#f9f5d7"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-toml codeBlock_bY9V thin-scrollbar" style="color:#654735;background-color:#f9f5d7"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#654735"><span class="token plain">[dependencies]</span><br></div><div class="token-line" style="color:#654735"><span class="token plain">confval = { version = "0.4", features = ["derive", "hcl", "color"] }</span><br></div></code></pre></div></div>]]></content>
        <author>
            <name>Ethan Hann</name>
            <uri>https://ethanhann.com</uri>
        </author>
        <category label="release" term="release"/>
    </entry>
</feed>