57/K1: A module declares its config with type, description and validation (issue 660) #320

Merged
mesh-admin merged 4 commits from pkg/57-k1-config-declaration into feat/57-config-and-provisioning 2026-10-14 05:25:35 +00:00
Contributor

Design 57 package K1 (issue 660, ADR 0348 §1, §4, §5, §6, §8, §11).

What changed

  • The manifest takes config, takes-config and ${config:<key>}, with settings, takes-settings and ${setting:<key>} read as aliases. A config value declares type (number, string, boolean; object or list only when trusted), description, validation (enum, minimum, maximum, pattern, the pattern matching the whole value), trusted, optional predefined, default or required, and a new per-value runtime: true for a value the module's code reads itself.
  • One composition path. Manifest.UnmarshalJSON reads the config form into the fields the settings form fills (Settings, a mergeable file's takes-settings, ${setting:<key>}), and MarshalJSON writes it back in the config form. So ${config:<key>} fills exactly as ${setting:<key>} does, and the mesh holds the manifest as its author wrote it. A settings declaration is written byte for byte as before.
  • A module uses one form or the other. A manifest mixing them is refused, naming the words of each form it uses.
  • Registration refuses, for a module in the config form, each rule of design 57's K1 (new internal/catalogue/config.go, ConfigProblems), each by name with what to do:
    1. a value without type or description;
    2. a value with neither default nor required (or both);
    3. a default failing its validation (type, enum, minimum, maximum, pattern), and validation that does not fit the type;
    4. an object or list not trusted;
    5. a predefined key not on the list or of another type. The list arrives with K2, so for now any predefined is refused saying the list is not yet present. The check against the list is built and tested with a stand-in list (predefinedKeys); K2 only has to fill it;
    6. an untrusted value falling back to a trusted predefined key (same: refused as not yet present until K2);
    7. a value neither placed (${config:} in a file, unit, owner, contribution or served fact, or named in a takes-config) nor runtime: true. This is skipped while the manifest still names templates, and judged again once their text is read (WithTemplatesFrom, Resolve);
    8. a placeholder naming an undeclared value;
    9. a reload-on or restart-on naming a file the module does not declare. Allowed: its own resource ids, another module's <module>.<id>, and the ids the mesh composes for it (composed-jails, filtering, certificate, certificate-authority, bus-users, secret-*, bound-*, needs-*, received-*, grant-*, access-*);
    10. a mergeable file not naming its keys under takes-config;
    11. a mesh word (already refused for both forms) or puid/pgid in takes-config.
  • Kept as it is: a module in the settings form keeps today's rules (SettingProblems, TakenSettingsProblems, WrittenSettingsProblems). Config-form fields under settings, and kind/why under config, are refused and the refusal says which form to use. A required value nothing sets composes as today's operator-own setting does: it is refused by name at composition (UnsetSettingError). Rules shared with the settings form are said in the config form's words for a module in the config form.

Deliberate choices, for the reviewer

  • Rules 9 (reload-on/restart-on) and the operator's-word heuristic (a key such as domain must be required, not defaulted) apply only to modules in the config form. ADR 0348 §11 says a module not yet moved keeps today's form. Repositories outside the catalogue (the media catalogue and the applications, package T6) are not checked here.
  • A takes-config key does not have to be declared under config. K1's list does not include that refusal, but ADR 0348 §4 implies it. I left it for the packages that move modules (T2–T5) or for R1 to decide.

Left for other packages

  • The declared-config bucket (F3, #315, internal/inventory/mirrors.go): #315 was not merged when I started, so this pull request does not widen it. Once #315 merges, the bucket's value should carry the new named fields of SettingDeclaration (type, description, enum, minimum, maximum, pattern, trusted, predefined, required, runtime). They are on the struct and in its JSON, so this needs no new reading, only the bucket's value type.
  • The list of predefined keys: K2 (issue 661) fills predefinedKeys.

How it is proven

Tests in internal/catalogue/config_test.go. They failed before this change (they did not compile without it) and pass now:

  • one refusal test per rule: TestConfigRefusesAValueWithoutTypeOrDescription, …WithNeitherDefaultNorRequired, …ADefaultFailingItsValidation, …AnObjectOrListNotTrusted, …APredefinedKeyNotOnTheListOrOfAnotherType, …AnUntrustedValueFallingBackToATrustedKey, …AValueNeitherPlacedNorReadAtRuntime, …APlaceholderNamingAnUndeclaredValue, …AReloadOrRestartOnNamingAnUndeclaredFile, …AMergeableFileNotNamingItsKeys, …AMeshWordOrAnAccountFactInTakesConfig;
  • the forms: TestAManifestMixingTheConfigAndSettingsFormsIsRefused, TestEachFormKeepsItsOwnDeclaration, TestAModuleInTheConfigFormRegisters, TestAConfigManifestIsWrittenBackInItsOwnForm, TestASettingsManifestIsWrittenBackAsBefore;
  • byte-identical composition: TestAModuleRewrittenFromSettingsToConfigComposesByteIdentically. dunst is written in both forms and composed on a machine with no layer, with the node's layer, and with the mesh's layer under the node's. The composed declarations are equal byte for byte.

Every catalogue manifest still registers. I built a controller from this branch and ran mesh-controller module check modules/*/module.json over mesh-catalog main (128 manifests) and over its feat/57-config-and-provisioning branch (128 manifests). Both exit 0. Their output is identical, byte for byte, to that of a controller built from the base branch at dc36536. The real dunst manifest rewritten to config also passes module check.

Reviewer's checklist

  1. Does what issue 660's Expected and design 57's K1 say, and nothing outside it. The change touches internal/catalogue only: the new config.go, plus small hooks in manifest.go (UnmarshalJSON, MarshalJSON, ParseManifest), setting_defaults.go (declaration fields; Effective skips a value with no default) and setting_takes.go (WrittenSettingsProblems defers to ConfigProblems for the config form). It does not touch F2's functions (settings.go, inventory/catalogue.go, modules.go), F3's or V1's. It is rebased on F2 #316 and V1 #317 as merged.
  2. There is one refusal test per rule, and all of them failed before. No existing test changed.
  3. Nothing changes for a module that has not moved. There is a byte-identical composition test, and module check output is identical over both catalogue branches.
  4. No secret, no store change and no migration.
  5. The strict parser accepts the new fields: SettingDeclaration's fields are decoded with unknown fields refused, and config/takes-config are read before anything writes them. The node-engine is untouched, because composition output is unchanged.
  6. gofmt -l cmd internal examples prints nothing; go vet ./... passes; sh merge-check.sh exits 0 with MESH_TEST_POSTGRES set to a throwaway PostgreSQL. That run includes go test -race ./... and every listed store test, which all passed.
  7. The words are config, config value, predefined key and node-engine. The old words appear only as the aliases' names.
Design 57 package K1 (issue 660, ADR 0348 §1, §4, §5, §6, §8, §11). ## What changed - **The manifest takes `config`, `takes-config` and `${config:<key>}`**, with `settings`, `takes-settings` and `${setting:<key>}` read as aliases. A config value declares `type` (number, string, boolean; object or list only when trusted), `description`, validation (`enum`, `minimum`, `maximum`, `pattern`, the pattern matching the whole value), `trusted`, optional `predefined`, `default` or `required`, and a new per-value `runtime: true` for a value the module's code reads itself. - **One composition path.** `Manifest.UnmarshalJSON` reads the config form into the fields the settings form fills (Settings, a mergeable file's takes-settings, `${setting:<key>}`), and `MarshalJSON` writes it back in the config form. So `${config:<key>}` fills exactly as `${setting:<key>}` does, and the mesh holds the manifest as its author wrote it. A settings declaration is written byte for byte as before. - **A module uses one form or the other.** A manifest mixing them is refused, naming the words of each form it uses. - **Registration refuses, for a module in the config form, each rule of design 57's K1** (new `internal/catalogue/config.go`, `ConfigProblems`), each by name with what to do: 1. a value without type or description; 2. a value with neither default nor required (or both); 3. a default failing its validation (type, enum, minimum, maximum, pattern), and validation that does not fit the type; 4. an object or list not trusted; 5. a predefined key not on the list or of another type. The list arrives with K2, so for now any `predefined` is refused saying the list is not yet present. The check against the list is built and tested with a stand-in list (`predefinedKeys`); K2 only has to fill it; 6. an untrusted value falling back to a trusted predefined key (same: refused as not yet present until K2); 7. a value neither placed (`${config:}` in a file, unit, owner, contribution or served fact, or named in a `takes-config`) nor `runtime: true`. This is skipped while the manifest still names templates, and judged again once their text is read (`WithTemplatesFrom`, `Resolve`); 8. a placeholder naming an undeclared value; 9. a `reload-on` or `restart-on` naming a file the module does not declare. Allowed: its own resource ids, another module's `<module>.<id>`, and the ids the mesh composes for it (`composed-jails`, `filtering`, `certificate`, `certificate-authority`, `bus-users`, `secret-*`, `bound-*`, `needs-*`, `received-*`, `grant-*`, `access-*`); 10. a mergeable file not naming its keys under `takes-config`; 11. a mesh word (already refused for both forms) or `puid`/`pgid` in `takes-config`. - **Kept as it is:** a module in the settings form keeps today's rules (`SettingProblems`, `TakenSettingsProblems`, `WrittenSettingsProblems`). Config-form fields under `settings`, and `kind`/`why` under `config`, are refused and the refusal says which form to use. A required value nothing sets composes as today's operator-own setting does: it is refused by name at composition (`UnsetSettingError`). Rules shared with the settings form are said in the config form's words for a module in the config form. ## Deliberate choices, for the reviewer - Rules 9 (reload-on/restart-on) and the operator's-word heuristic (a key such as `domain` must be `required`, not defaulted) apply only to modules in the config form. ADR 0348 §11 says a module not yet moved keeps today's form. Repositories outside the catalogue (the media catalogue and the applications, package T6) are not checked here. - A `takes-config` key does not have to be declared under `config`. K1's list does not include that refusal, but ADR 0348 §4 implies it. I left it for the packages that move modules (T2–T5) or for R1 to decide. ## Left for other packages - **The declared-config bucket** (F3, #315, `internal/inventory/mirrors.go`): #315 was not merged when I started, so this pull request does not widen it. Once #315 merges, the bucket's value should carry the new named fields of `SettingDeclaration` (type, description, enum, minimum, maximum, pattern, trusted, predefined, required, runtime). They are on the struct and in its JSON, so this needs no new reading, only the bucket's value type. - The list of predefined keys: K2 (issue 661) fills `predefinedKeys`. ## How it is proven Tests in `internal/catalogue/config_test.go`. They failed before this change (they did not compile without it) and pass now: - one refusal test per rule: `TestConfigRefusesAValueWithoutTypeOrDescription`, `…WithNeitherDefaultNorRequired`, `…ADefaultFailingItsValidation`, `…AnObjectOrListNotTrusted`, `…APredefinedKeyNotOnTheListOrOfAnotherType`, `…AnUntrustedValueFallingBackToATrustedKey`, `…AValueNeitherPlacedNorReadAtRuntime`, `…APlaceholderNamingAnUndeclaredValue`, `…AReloadOrRestartOnNamingAnUndeclaredFile`, `…AMergeableFileNotNamingItsKeys`, `…AMeshWordOrAnAccountFactInTakesConfig`; - the forms: `TestAManifestMixingTheConfigAndSettingsFormsIsRefused`, `TestEachFormKeepsItsOwnDeclaration`, `TestAModuleInTheConfigFormRegisters`, `TestAConfigManifestIsWrittenBackInItsOwnForm`, `TestASettingsManifestIsWrittenBackAsBefore`; - **byte-identical composition:** `TestAModuleRewrittenFromSettingsToConfigComposesByteIdentically`. dunst is written in both forms and composed on a machine with no layer, with the node's layer, and with the mesh's layer under the node's. The composed declarations are equal byte for byte. **Every catalogue manifest still registers.** I built a controller from this branch and ran `mesh-controller module check modules/*/module.json` over mesh-catalog `main` (128 manifests) and over its `feat/57-config-and-provisioning` branch (128 manifests). Both exit 0. Their output is identical, byte for byte, to that of a controller built from the base branch at dc36536. The real dunst manifest rewritten to `config` also passes `module check`. ## Reviewer's checklist 1. [x] Does what issue 660's Expected and design 57's K1 say, and nothing outside it. The change touches `internal/catalogue` only: the new `config.go`, plus small hooks in `manifest.go` (UnmarshalJSON, MarshalJSON, ParseManifest), `setting_defaults.go` (declaration fields; `Effective` skips a value with no default) and `setting_takes.go` (`WrittenSettingsProblems` defers to `ConfigProblems` for the config form). It does not touch F2's functions (settings.go, inventory/catalogue.go, modules.go), F3's or V1's. It is rebased on F2 #316 and V1 #317 as merged. 2. [x] There is one refusal test per rule, and all of them failed before. No existing test changed. 3. [x] Nothing changes for a module that has not moved. There is a byte-identical composition test, and `module check` output is identical over both catalogue branches. 4. [x] No secret, no store change and no migration. 5. [x] The strict parser accepts the new fields: `SettingDeclaration`'s fields are decoded with unknown fields refused, and `config`/`takes-config` are read before anything writes them. The node-engine is untouched, because composition output is unchanged. 6. [x] `gofmt -l cmd internal examples` prints nothing; `go vet ./...` passes; `sh merge-check.sh` exits 0 with `MESH_TEST_POSTGRES` set to a throwaway PostgreSQL. That run includes `go test -race ./...` and every listed store test, which all passed. 7. [x] The words are config, config value, predefined key and node-engine. The old words appear only as the aliases' names.
mesh-admin added 3 commits 2026-10-14 01:39:50 +00:00
The manifest's hooks for the config form: read into the fields the settings form fills, written back as read, and judged by ConfigProblems; the rules are in config.go.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The config form's declaration and its registration refusals, each by name with what to do (ADR 0348, design 57 package K1).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Prove each config refusal and the byte-identical composition of a module moved to config (issue 660)
mesh/merge-gate out of date: judged against trunk dc36536e199e, the trunk is now 60d390adeddc; judged again on a recheck or when it is merged
mesh/repo-check out of date: judged against trunk dc36536e199e, the trunk is now 60d390adeddc; judged again on a recheck or when it is merged
mesh/delivery superseded: a newer head of the same pull request
ae071e2b59
One registration refusal test per rule of design 57 package K1, the forms kept apart and written back as read, and dunst rewritten from settings to config composing to the same bytes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Author
Contributor

Delivery novox/mesh-controller@9aa033269495 — delivered since 2026-10-14T05:25:55Z

Delivery plan — builds nothing: the change touches no module of the mesh's graph

Transitions

  • 2026-10-14 05:17 (new) → proposed (announced): novox/mesh-controller#320's head announced
  • 2026-10-14 05:21 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit
  • 2026-10-14 05:21 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
  • 2026-10-14 05:25 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move
  • 2026-10-14 05:25 published → delivered (done): nothing for a walk to move

The commit's note under refs/notes/mesh-plan keeps every transition: git log --notes=mesh-plan.

<!-- mesh-delivery:view --> **Delivery** `novox/mesh-controller@9aa033269495` — **delivered** since 2026-10-14T05:25:55Z **Delivery plan** — builds nothing: the change touches no module of the mesh's graph **Transitions** - 2026-10-14 05:17 (new) → proposed (announced): novox/mesh-controller#320's head announced - 2026-10-14 05:21 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit - 2026-10-14 05:21 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail - 2026-10-14 05:25 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move - 2026-10-14 05:25 published → delivered (done): nothing for a walk to move The commit's note under `refs/notes/mesh-plan` keeps every transition: `git log --notes=mesh-plan`.
mesh-admin left a comment
Author
Contributor

Verdict: CHANGES at ae071e2b59

Independent review of K1 (issue 660), checked against ADR 0348 §1, §4, §5, §11 and How it is checked, and design 57's K1.

What I ran (worktree at ae071e2, base dc36536):

  • gofmt -l cmd internal examples printed nothing. go vet ./... passed.
  • sh merge-check.sh with a throwaway PostgreSQL on 127.0.0.1:55432 (dynamic_shared_memory_type=mmap) exited 0. It ran with the race detector, and every listed store test passed.
  • I built controllers from the head and the base and ran module check modules/*/module.json over mesh-catalog main (ebf7f37, 128 manifests) and feat/57 (8aa37e8, 128 manifests). All four runs exited 0, and the head's output matched the base's byte for byte.
  • I wrote a throwaway test that parses each of those 256 manifests (with its templates read in), writes it back, reads it again and writes it again. The bytes are identical between head and base, so the settings form is written back unchanged.
  • I wrote a round-trip probe for the config form covering enum, minimum, maximum, pattern, a default of 0, false and "", a trusted object, a trusted required list, runtime and required. Written back, its config and resources are semantically equal to the input, no key is lost, and the declarations are equal when read again.
  • I reverted the non-test files and the new tests no longer compile, so they fail without the change.

What I found holds:

  • (a) The config form is read into the settings form's fields, so there is one composition path, and it is written back in the config form.
  • (b) A mixed manifest is refused in every variant I probed: config beside settings, settings with takes-config, and ${setting:} in a config module.
  • (c) All eleven refusals fire for a module in the config form. TypedSettingProblems refuses only fields that the strict parser refused before as unknown fields, so no settings-form manifest is newly refused.
  • (d) The dunst byte-identical composition test is sound.
  • (e) takes-* is stripped at composition (settings.go:116), and the declarations compose byte-identically, so nothing new reaches the node-engine's strict parse. An unknown field under config is still refused.

Findings:

  1. MUST: internal/catalogue/config.go:401-406 (configTakesProblems) accepts a takes-config key that is not declared under config. I confirmed this with a probe: takes-config: ["position","theme","nobody-declared"] registers. ADR 0348 §4 says "A module declares every value it reads". A mergeable file's taken key is a value the module reads, so §4 requires this refusal. §11 only says every mergeable file names its keys, and How it is checked does not list the refusal explicitly. There are three reasons to change it now. First, an undeclared key has no type, validation or trusted mark, so a mergeable file could take a value that decides what runs without §8's trusted rule applying. Second, §10's config verb refuses undeclared keys, so such a key could never be set. Third, no module uses the config form yet, so adding the refusal now refuses nothing, while adding it after T2–T5 move modules could refuse modules that have already moved. Refuse an undeclared key in takes-config for the config form, with a test.
  2. SHOULD (can follow): internal/catalogue/setting_into.go:78, 134 and 233. For a module in the config form, an unset required value is refused at composition in the settings form's words: "says ${setting:sender} … settings set notifier <file>". My probe TestRVRequiredUnset shows this. inConfigWords covers only the registration problems. Say it in the config form's words when m.DeclaresConfig(), or leave it to K3, which replaces the verb.
  3. NIT: internal/catalogue/config.go:282-283 says the placed rule is "judged again" in Resolve. Manifest.Resolve does not re-parse. It is re-judged only because its callers (the merge gate at merge_gate.go:608-613 and the controller's take-in at build.go:801) marshal the result and parse it again. Composing Resolve's output in memory leaves ${config:} unfilled, and the unconsumed-placeholder rule refuses it loudly, so this is not a bug today. Reword the comment to name the callers.
Verdict: CHANGES at ae071e2b59ee25698582d17bfb070329e2b3d02f Independent review of K1 (issue 660), checked against ADR 0348 §1, §4, §5, §11 and How it is checked, and design 57's K1. What I ran (worktree at ae071e2, base dc36536): - `gofmt -l cmd internal examples` printed nothing. `go vet ./...` passed. - `sh merge-check.sh` with a throwaway PostgreSQL on 127.0.0.1:55432 (dynamic_shared_memory_type=mmap) exited 0. It ran with the race detector, and every listed store test passed. - I built controllers from the head and the base and ran `module check modules/*/module.json` over mesh-catalog main (ebf7f37, 128 manifests) and feat/57 (8aa37e8, 128 manifests). All four runs exited 0, and the head's output matched the base's byte for byte. - I wrote a throwaway test that parses each of those 256 manifests (with its templates read in), writes it back, reads it again and writes it again. The bytes are identical between head and base, so the settings form is written back unchanged. - I wrote a round-trip probe for the config form covering enum, minimum, maximum, pattern, a default of 0, false and "", a trusted object, a trusted required list, runtime and required. Written back, its `config` and `resources` are semantically equal to the input, no key is lost, and the declarations are equal when read again. - I reverted the non-test files and the new tests no longer compile, so they fail without the change. What I found holds: - (a) The config form is read into the settings form's fields, so there is one composition path, and it is written back in the config form. - (b) A mixed manifest is refused in every variant I probed: `config` beside `settings`, `settings` with `takes-config`, and `${setting:}` in a config module. - (c) All eleven refusals fire for a module in the config form. `TypedSettingProblems` refuses only fields that the strict parser refused before as unknown fields, so no settings-form manifest is newly refused. - (d) The dunst byte-identical composition test is sound. - (e) `takes-*` is stripped at composition (settings.go:116), and the declarations compose byte-identically, so nothing new reaches the node-engine's strict parse. An unknown field under `config` is still refused. Findings: 1. MUST: internal/catalogue/config.go:401-406 (`configTakesProblems`) accepts a `takes-config` key that is not declared under `config`. I confirmed this with a probe: `takes-config: ["position","theme","nobody-declared"]` registers. ADR 0348 §4 says "A module declares every value it reads". A mergeable file's taken key is a value the module reads, so §4 requires this refusal. §11 only says every mergeable file names its keys, and How it is checked does not list the refusal explicitly. There are three reasons to change it now. First, an undeclared key has no type, validation or trusted mark, so a mergeable file could take a value that decides what runs without §8's trusted rule applying. Second, §10's `config` verb refuses undeclared keys, so such a key could never be set. Third, no module uses the config form yet, so adding the refusal now refuses nothing, while adding it after T2–T5 move modules could refuse modules that have already moved. Refuse an undeclared key in `takes-config` for the config form, with a test. 2. SHOULD (can follow): internal/catalogue/setting_into.go:78, 134 and 233. For a module in the config form, an unset required value is refused at composition in the settings form's words: "says ${setting:sender} … `settings set notifier <file>`". My probe TestRVRequiredUnset shows this. `inConfigWords` covers only the registration problems. Say it in the config form's words when `m.DeclaresConfig()`, or leave it to K3, which replaces the verb. 3. NIT: internal/catalogue/config.go:282-283 says the placed rule is "judged again" in `Resolve`. `Manifest.Resolve` does not re-parse. It is re-judged only because its callers (the merge gate at merge_gate.go:608-613 and the controller's take-in at build.go:801) marshal the result and parse it again. Composing `Resolve`'s output in memory leaves `${config:}` unfilled, and the unconsumed-placeholder rule refuses it loudly, so this is not a bug today. Reword the comment to name the callers.
mesh-admin added 1 commit 2026-10-14 05:17:28 +00:00
Refuse an undeclared takes-config key, and say an unset required value in the config form's words
mesh/merge-gate head 9aa033269495 merged into trunk 60d390adeddc — pass: the change touches no module of the mesh's graph
mesh/repo-check head 9aa033269495 merged into trunk 60d390adeddc — pass: its merge-check.sh passed
mesh/delivery delivered
9aa0332694
A key a mergeable file took had no type, validation or trusted mark, and the config verb could never set it (ADR 0348 §4). A required config value nothing sets was refused naming ${setting:} and settings set, words the module does not use. Review of mesh-controller#320 (issue 660).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Author
Contributor

Verdict: APPROVE at 9aa0332

Re-review of the three findings of review 264.

  1. An undeclared takes-config key is refused by name (config.go configTakesProblems). TestConfigRefusesATakesConfigKeyNotDeclared fails with the config.go change reverted ("registered; wanted a refusal saying ...") and passes with it.
  2. A config-form module's unset required value is refused in the config form's words (unsetInConfigWords: ${config:sender}, "required config value", the config verb), and the settings form keeps its words. TestAnUnsetRequiredValueIsRefusedInTheConfigFormsWords fails with the two call sites reverted and passes with them.
  3. The comment in config.go is corrected.

Checked:

  • git diff --stat ae071e2..9aa0332: only config.go, config_test.go, declaration.go, setting_into.go, settings.go; nothing else changed.
  • module check over mesh-catalog main (af5cf53) and its feat/57 branch (8aa37e8), a controller built from head against one built from the PR base dc36536: output identical (131 lines each, exit 0).
  • gofmt -l: clean. go vet ./...: clean. merge-check.sh with a throwaway PostgreSQL 18 over TCP 127.0.0.1: all tests pass under the race detector, all listed store tests ran and passed. Postgres stopped afterwards.
  • git merge-tree of the head with origin/feat/57 (at 60d390a, F2b #321 merged): clean, no conflicts.

Note, not for this pull request: merge-check.sh as shipped fails the store-tests drop check, because origin/main in the clone now carries #319 (two provider-hold tests added to testdata/store-tests) that feat/57 does not have yet. Run against the merge base instead of origin/main, it passes (exit 0). Merging main into feat/57 clears this for every package.

Verdict: APPROVE at 9aa0332 Re-review of the three findings of review 264. 1. An undeclared takes-config key is refused by name (config.go configTakesProblems). TestConfigRefusesATakesConfigKeyNotDeclared fails with the config.go change reverted ("registered; wanted a refusal saying ...") and passes with it. 2. A config-form module's unset required value is refused in the config form's words (unsetInConfigWords: ${config:sender}, "required config value", the config verb), and the settings form keeps its words. TestAnUnsetRequiredValueIsRefusedInTheConfigFormsWords fails with the two call sites reverted and passes with them. 3. The comment in config.go is corrected. Checked: - git diff --stat ae071e2..9aa0332: only config.go, config_test.go, declaration.go, setting_into.go, settings.go; nothing else changed. - module check over mesh-catalog main (af5cf53) and its feat/57 branch (8aa37e8), a controller built from head against one built from the PR base dc36536: output identical (131 lines each, exit 0). - gofmt -l: clean. go vet ./...: clean. merge-check.sh with a throwaway PostgreSQL 18 over TCP 127.0.0.1: all tests pass under the race detector, all listed store tests ran and passed. Postgres stopped afterwards. - git merge-tree of the head with origin/feat/57 (at 60d390a, F2b #321 merged): clean, no conflicts. Note, not for this pull request: merge-check.sh as shipped fails the store-tests drop check, because origin/main in the clone now carries #319 (two provider-hold tests added to testdata/store-tests) that feat/57 does not have yet. Run against the merge base instead of origin/main, it passes (exit 0). Merging main into feat/57 clears this for every package.
mesh-admin merged commit 221fe5a60d into feat/57-config-and-provisioning 2026-10-14 05:25:35 +00:00
mesh-admin deleted branch pkg/57-k1-config-declaration 2026-10-14 05:25:35 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: novox/mesh-controller#320