# integration-config-declaration Specification ## Purpose Keep configuration ownership aligned with code ownership: every key an integration consumes is declared by that integration's `ConfigSpec` and registered generically by the composition root, whatever its type, so core never hand-declares or reads an integration-namespaced key. Core capabilities configured by deployment get core-namespaced keys, and integrations that need a core-resolved value receive it as threaded data rather than reaching for viper themselves. ## Requirements ### Requirement: Integration config keys travel the ConfigSpec seam regardless of type Every configuration key an integration consumes SHALL be declared in that integration's `ConfigSpec`, and the composition root SHALL register a matching CLI flag and default for each declared key generically, for all supported key types: string, string-slice, boolean, and duration. A key's type SHALL be carried by its declared `Default` value. Core SHALL NOT hand-declare flags or defaults for any integration-namespaced key. #### Scenario: Boolean and duration keys register through the generic seam - **WHEN** an integration's `ConfigSpec` declares a key with a `bool` default and a key with a `time.Duration` default - **THEN** `member-console start --help` SHALL list both keys as flags of the matching type - **AND** their declared defaults SHALL apply when the keys are unset #### Scenario: FedWiki's sync knobs are integration-declared - **WHEN** the composition root's flag declarations are inspected - **THEN** `fedwiki-sync-enabled`, `fedwiki-sync-interval`, `fedwiki-sync-trigger-immediately`, and `fedwiki-swap-cooldown` SHALL be declared only by fedwiki's `ConfigSpec`, not hand-declared in core #### Scenario: Discourse's sync knobs are declared, not implicit - **WHEN** discourse's `ConfigSpec` is inspected - **THEN** `discourse-sync-interval` and `discourse-sync-trigger-immediately` SHALL be declared with defaults matching the integration's runtime fallbacks - **AND** unset keys SHALL produce the same behavior as before declaration ### Requirement: Core reads no integration-namespaced configuration key Core packages (`cmd/`, `internal/server/`, `internal/workflows/`) SHALL NOT read integration-namespaced configuration keys to configure core capabilities. Core capabilities configured by deployment SHALL use core-namespaced keys; where an integration needs a core-resolved value, the composition root SHALL resolve it once and thread it as data. Exception, tracked as existing debt: the composition root still reads Stripe's declared keys to construct core's payments baseline — that extraction is `payments-provider-seam` (issues.md), not this requirement's scope. #### Scenario: The domains connect target is a core key - **WHEN** a deployment sets `domains-connect-target` - **THEN** the member Domains surface, the claim-verification worker probe, and fedwiki's create-flow gate SHALL all observe that value - **AND** no code SHALL read `fedwiki-custom-domain-target` (the key no longer exists) #### Scenario: Empty core connect target disables external claims deployment-wide - **WHEN** `domains-connect-target` is unset - **THEN** external-claim creation SHALL be disabled everywhere the gate applies, matching the domains-registry gate requirement #### Scenario: FedWiki receives the connect target as data - **WHEN** fedwiki's route registration constructs its external-claim gate - **THEN** the connect target SHALL arrive via `server.Deps`, not via a viper read inside the integration