Stop a settings layer replacing what a provider serves (issue 696)
mesh/merge-gate head c5fe7d4795d7 merged into trunk dc36536e199e — pass: the change touches no module of the mesh's graph
mesh/repo-check head c5fe7d4795d7 merged into trunk dc36536e199e — pass: its merge-check.sh passed
mesh/delivery delivered
mesh/delivery-group group pkg/57-f2b-served-keys delivered: every member is delivered
mesh/merge-gate head c5fe7d4795d7 merged into trunk dc36536e199e — pass: the change touches no module of the mesh's graph
mesh/repo-check head c5fe7d4795d7 merged into trunk dc36536e199e — pass: its merge-check.sh passed
mesh/delivery delivered
mesh/delivery-group group pkg/57-f2b-served-keys delivered: every member is delivered
What a provider serves is its definition's (ADR 0348 clause 11): a layer
fills only the keys it asks for as ${setting:<key>}. Settle replaced any
served key a layer named, so a setting for one of a provider's files could
change what every consumer was told. influxdb on ace was the one live layer
relying on it and now serves its settings (mesh-catalog, merged first), so
grafana's data source composes byte for byte as before. UnusedSettings no
longer counts a literal served key as a place a setting lands.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -117,25 +117,27 @@ func ApplySettings(resource map[string]any, layers []Layer) (map[string]any, err
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Settle lays settings over what a provider serves. Exported because a served fact is settled where
|
||||
// the mesh is walked rather than where a node is declared.
|
||||
// Settle fills what a provider serves from its settings. Exported because a served fact is settled
|
||||
// where the mesh is walked rather than where a node is declared.
|
||||
//
|
||||
// **A setting overrides a served key; it never adds one** (novox/hq 04-ISSUES/173). What a consumer
|
||||
// is told is the provider's contract, and a setting made for one of the provider's files — a site
|
||||
// name, a public address — is not part of it. Before this, every setting of a module reached every
|
||||
// consumer of every provision it served.
|
||||
// **What a provider serves is its definition's; a layer replaces none of it** (novox/hq ADR 0348
|
||||
// clause 11, issue 696). A served value is filled from the layers only where the definition asks,
|
||||
// with `${setting:<key>}` (ADR 0155) — a mail provider's domain, an identity provider's issuer, a
|
||||
// time-series store's org and bucket — and a layer that sets a key the provider serves as a literal
|
||||
// changes nothing a consumer is told. Nor does a setting add a key (novox/hq 04-ISSUES/173): a
|
||||
// setting made for one of the provider's files — a site name, a public address — is not part of the
|
||||
// contract. Until issue 696, a layer replaced any served key it named; influxdb on ace was the one
|
||||
// layer relying on it, and serves `${setting:org}` and `${setting:bucket}` since.
|
||||
func Settle(base map[string]any, layers []Layer) (map[string]any, error) {
|
||||
return overridden(base, layers, "what is served")
|
||||
return filledFromSettings(deepCopy(base), layers, "what is served")
|
||||
}
|
||||
|
||||
// overridden lays settings over a map whose keys are its contract: a contribution, a served fact.
|
||||
// Only the keys the map already declares are touched; the rest of a layer is somebody else's
|
||||
// business (a file's, another destination's) and is left to reach it there.
|
||||
// overridden lays settings over a contribution: a map whose keys are its contract. Only the keys the
|
||||
// map already declares are touched; the rest of a layer is somebody else's business (a file's,
|
||||
// another destination's) and is left to reach it there.
|
||||
//
|
||||
// A declared value may itself be the operator's, `${setting:<key>}` (ADR 0155): a mail provider
|
||||
// serves its domain, an identity provider its issuer, and neither is the definition's to state.
|
||||
// Filled from the layers after the overrides, and refused by name when nothing sets it — a literal
|
||||
// placeholder handed to a consumer is a service configured against a string nobody meant.
|
||||
// A declared value may itself be the operator's, `${setting:<key>}` (ADR 0155), filled after the
|
||||
// overrides (filledFromSettings).
|
||||
func overridden(base map[string]any, layers []Layer, what string) (map[string]any, error) {
|
||||
kept := make([]Layer, 0, len(layers))
|
||||
for _, layer := range layers {
|
||||
@@ -151,6 +153,14 @@ func overridden(base map[string]any, layers []Layer, what string) (map[string]an
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return filledFromSettings(merged, layers, what)
|
||||
}
|
||||
|
||||
// filledFromSettings fills each `${setting:<key>}` in a map's top-level strings from the layers,
|
||||
// later beating earlier and a module's defaults lowest, and refuses one nothing sets by name — a
|
||||
// literal placeholder handed to a consumer is a service configured against a string nobody meant.
|
||||
// It fills merged in place and returns it.
|
||||
func filledFromSettings(merged map[string]any, layers []Layer, what string) (map[string]any, error) {
|
||||
for key, value := range merged {
|
||||
s, ok := value.(string)
|
||||
if !ok {
|
||||
@@ -177,7 +187,8 @@ func overridden(base map[string]any, layers []Layer, what string) (map[string]an
|
||||
// module says what it means by default, and somebody says what it means here. A contribution that
|
||||
// could not be settled would have to be edited to be reused anywhere else. The two differ in one
|
||||
// respect, and the caller decides it: a file takes keys it did not declare (a setting may add to a
|
||||
// configuration), a contribution or served fact does not (overridden).
|
||||
// configuration), a contribution does not (overridden). A served fact takes no layer at all; only
|
||||
// its ${setting:<key>} is filled (Settle).
|
||||
func settle(base map[string]any, layers []Layer, protected map[string]bool, what string) (
|
||||
map[string]any, error) {
|
||||
merged := deepCopy(base)
|
||||
@@ -353,8 +364,9 @@ func sortedKeysAny(m map[string]any) []string {
|
||||
// way there is. This is what makes that visible at the moment they set it.
|
||||
//
|
||||
// Where a key can land: any mergeable file takes any key; a file asking for `${setting:<key>}`
|
||||
// takes that key (ADR 0155); a contribution or a served fact takes a key it declares, and no other
|
||||
// (novox/hq 04-ISSUES/173); and the mesh's own words — `expose`, `ports`, `reach`, `endpoints` —
|
||||
// takes that key (ADR 0155); a contribution takes a key it declares, and no other (novox/hq
|
||||
// 04-ISSUES/173); a served fact takes only the keys it asks for as `${setting:<key>}`, since a layer
|
||||
// replaces no served key (novox/hq issue 696); and the mesh's own words — `expose`, `ports`, `reach`, `endpoints` —
|
||||
// are read by the mesh. A key none of those takes is stray, and is said so rather than dropped.
|
||||
func UnusedSettings(m Manifest, layers []Layer) []string {
|
||||
named := namesItsKeys(m)
|
||||
@@ -397,11 +409,6 @@ func UnusedSettings(m Manifest, layers []Layer) []string {
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, served := range m.Serves {
|
||||
for key := range served {
|
||||
lands[key] = true
|
||||
}
|
||||
}
|
||||
var unused []string
|
||||
for _, layer := range layers {
|
||||
for key := range layer.Whole() {
|
||||
@@ -444,7 +451,7 @@ func UnusedSettings(m Manifest, layers []Layer) []string {
|
||||
}
|
||||
unused = append(unused, fmt.Sprintf(
|
||||
"%s sets %q, and %s has no file that merges it, asks for no ${setting:%s}, and "+
|
||||
"declares no %q in what it contributes or serves%s",
|
||||
"declares no %q in what it contributes%s",
|
||||
layer.From, key, m.Module, key, key, takenSaid(m)))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user