Repository navigation
Conversation
Unknown fields in a key config are ignored on main with no signal, so a misspelled kill switch such as ramp.remtoe keeps serving silently. The record keeps main's per-leaf fail-open rules, as the maintainer chose over strict validation, and proposes one config_unknown_field diagnostic per observed config, with every other decision open at the design gate.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #244 +/- ##
=======================================
Coverage 93.73% 93.73%
=======================================
Files 78 78
Lines 11357 11357
Branches 656 656
=======================================
+ Hits 10645 10646 +1
+ Misses 642 641 -1
Partials 70 70
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…ck cheap The maintainer chose in session that a static default with an unknown field fails closed, throwing where an invalid static value throws today (D6), and asked for no runtime overhead. Only provider replies now report, once per enabled call that reads one (D4), and the new D9 keeps the check off the hot path: typed configs never check, constructed configs answer from construction, raw maps compare their size with the known keys the merge already looks up. The change is now breaking in every port (D8).
The maintainer chose in session to drop static defaults from the change: they are typed code the service owns, so checking them buys little, and the throw would have stopped services whose untyped defaults run today. D6 now leaves them exactly as on main, the earlier fail-closed choice moves to Rejected, and the only breaking effect left is Rust's new ErrorKind variant.
This branch has not been deployed
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.
Problem
A key config field that DialCache does not know is ignored on
mainin every port, with no metric and no log. A misspelled emergency switch such asramp: { remtoe: 0 }keeps Redis serving, and nothing tells the operator why. Review of #138 found the same case for its logging group on 2026-08-15. Every other bad input already recordsconfig_resolutionwhen a call reads it. No issue exists; the gap came up while #242 was being designed.Change
This is a Portable behavior change: it adds a
CONTRACTS.mdobligation that every port mirrors. The record isdesign/2026-10-24-unknown-config-field-metric.md, and this pull request holds only the record until every decision is accepted.Two decisions are confirmed in session:
main's per-leaf consequences. Each enabled call whose provider reply carries an unknown field records oneerror{layer: noop, error: config_unknown_field}event, and a bounded warning names the field paths.main, neither checked nor reported. They are typed code the service owns, so checking them buys little. An earlier same-day choice to make them throw is recorded under D6's Rejected.The record also covers:
The record replaces the strict-validation plan that #242's D14 pointed to. D14's choice still holds: #242 adds no unknown-field reporting.
Open questions
Each decision below is
Openin the record. The recommendation is the record's Choice.ttlSecandrampmaps, inshadow, and inshadow.mismatchLoggingonce feat(shadow): log the paths of mismatching fields in confirmed-mismatch warnings #242 lands. A key counts whatever its value.shadowRampkeeps its whole-call failure. A Python field supplied under both spellings counts once, as unknown. Recommended.config_unknown_fielderror kind onnoop, plus one warning per use case. The warning names up to eight paths and repeats only when that use case's set of unknown paths changes. Recommended over reusingconfig_resolutionor adding a field-name label.config_resolution, because a TypeScript provider callingnew DialCacheKeyConfig(badJson)throws before DialCache sees the fields.DialCacheKeyConfigconstructor and PythonPolicykeep a private marker, so provider replies built from parsed JSON still report. Recommended.behaviorVersionbump, at the Full tier. Recommended over native-only tests.ErrorKindgaining a variant. The same change adds#[non_exhaustive]toErrorKindandDisabledReason. Before 1.0,featandfeat!both bump the minor version. Recommended.DialCacheKeyConfigor PythonPolicyanswers from construction. Raw Go, Rust and Python maps compare their size with the known keys the merge already looks up. TypeScript plain objects are remembered in aWeakMap. Only a config that carries an unknown field pays to name its paths. Recommended.config.ts,runtime-config.tsanddialcache.tsand adds themismatchLogginggroup (recommended), or stack on its branch.Validation
Head:
9cfb3b59cfb3b5: pending at the time of writing. Every commit touches one Markdown file underdesign/, which no ledger pins.Not run: the Full tier (D7) applies to the implementing commits, which wait for the design gate.
Follow-ups
go/engine.go) and Rust (rust/src/execution.rs) record the stale-ageconfig_resolutiononly in the coalescing leader, while TypeScript and Python record it for every caller. This is unconfirmed by a test, and no issue is filed yet.BREAKING CHANGE: Rust's public
ErrorKindenum gains theConfigUnknownFieldvariant, so a Rust caller that matches every variant must add an arm.ErrorKindandDisabledReasonalso become#[non_exhaustive], so later kinds will not break callers again. TypeScript, Go and Python gain only a newconfig_unknown_fielderror label value, and static defaults behave as before.