fix(validator): keep an inactive boolean branch out of schemas - #69
Merged
David Chicaiza (david0723) merged 2 commits intoSep 2, 2026
Merged
Conversation
The suppressed walk of a single-branch boolean's inactive branch pushed the branch's fields into `schemas`, flattened and still `required: true`. Consumers persist that list as the module's resolved form and validate runtime bundles against it without ever seeing the toggle, so the leaked field was demanded at run time. With `fillDefaults` filling the toggle to `false` this hit every module that predates the toggle.
Copilot started reviewing on behalf of
David Chicaiza (david0723)
September 2, 2026 09:54
View session
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
The behavioral change for two-branch boolean nested (registerOnly) affecting schemas isn’t covered by a regression test, and one newly added test name is unclear/grammatically incorrect.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Fixes validateForman(..., { schemas: true }) so fields from an inactive boolean nested branch are no longer emitted into the flattened schemas output, preventing downstream validators (that don’t see the toggle value) from incorrectly requiring fields from an inactive branch.
Changes:
- Skip pushing fields into
roots[domain].schemaFieldswhen walking undersuppressRequired(inactive single-branch boolean) andregisterOnly(inactive two-branch boolean) contexts. - Add regression tests for single-branch boolean nested to ensure inactive branches don’t leak into
schemas, including whenfillDefaultsfills the toggle tofalse.
File summaries
| File | Description |
|---|---|
src/validator.ts |
Prevents inactive boolean nested branches from contributing fields to schemas by gating schema-field collection on registerOnly / suppressRequired. |
test/boolean-nested.spec.ts |
Adds regression coverage for schemas output under single-branch boolean nested, including a fillDefaults scenario. |
Review details
- Files reviewed: 2/2 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
David Chicaiza (david0723)
requested a review
from Jakub Stok (jakubstokcelonis)
September 2, 2026 09:58
…hable guard The two-branch object form carries no per-branch domain, so the domain-root push site is only reached under `suppressRequired`; the `registerOnly` check there was dead. Pins: two-branch reports only the active branch, and a cross-domain single-branch inactive side stays out of that domain's schemas.
Milan Kyncl (milankyncl)
approved these changes
Sep 2, 2026
David Chicaiza (david0723)
deleted the
fix/inactive-boolean-branch-leaks-into-schemas
branch
September 2, 2026 10:12
Merged
David Chicaiza (david0723)
added a commit
that referenced
this pull request
Sep 2, 2026
Version bump to **2.0.1**. Includes: - #69: the inactive branch of a boolean toggle no longer leaks into `schemas` / `resolvedSchemas`. Those fields came out flat with `required: true`, and a consumer persisting that list as the module's resolved form then had the field demanded at run time by validators that never see the toggle. With `fillDefaults` filling the toggle to `false`, this was hitting every module that predates the toggle. Validation outcomes are unchanged. - #66: an RPC-backed option list that cannot see a reference value warns instead of failing. Patch, not minor: no new surface, two fixes. README carries the note. Once merged, creating the `v2.0.1` GitHub release triggers the npm + JSR publish workflows.
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.
Follow-up to #65.
What breaks
A single-branch boolean (
nested: [...], applies whentrue) with the toggle atfalseis still walked since 1.18.0 so stale values keep their type rules. That walk also pushed the branch's fields intoschemas, flattened, withrequired: trueintact.Consumers persist
schemasas the module's resolved form and validate runtime bundles against it. Those validators never see the toggle, so a required field from the inactive branch gets demanded at run time, e.g.Missing value of required parameter 'fallbackConnectionId'on a module whose fallback toggle isfalse.Why it surfaced now
Before #65 an absent toggle failed as mandatory and never reached the walk, so the leak only fired when the caller sent
falseexplicitly. WithfillDefaults: 'requiredOnly'the toggle fills tofalseand the inactive walk runs on every module that predates the toggle, which is most of them. The fill was correct; what it exposed was this.The fix
suppressRequiredhas exactly one setter, the inactive single-branch walk, so bothschemaFields.pushsites now skip when it is set: the nested site (same-domain branches) and the domain-root site (a single-branchnested: { domain, store }pointing at another domain). The two-branch form already stayed out ofschemasviaregisterOnly; a test now pins that.Validation itself is unchanged: stale values in the inactive branch are still type-checked, strict mode still knows their names, and an active branch still lands in
schemasexactly as before.Tests
Five cases in
boolean-nested.spec.ts: explicitfalseleaves the branch out,truekeeps it in, afalsethatfillDefaultsfilled leaves it out, a cross-domain inactive branch stays out of the other domain'sschemas, and the two-branch form reports only its active side (the last one is a pin, it passed before). The first four go red on main. 508/508 green, tsc and build clean.Not in this PR
statesfor the inactive branch is untouched. It carries labels for stale values, nothing a runtime validator reads. Happy to align it in a follow-up if you'd rather the inactive branch contribute nothing at all.schemasspreads anrpc://string sitting inside a collectionspecinto an indexed-character object ({"0":"r","1":"p",...}). Separate defect in the same output, I'll file it rather than widen this one.