# ADR 0027: VS-NfD hardening-profile mode and configuration catalog - Status: accepted (2026-07-31) - Date: 2026-07-31 ## Context The hardening guide (issue #227, `docs/vs-nfd/50-haertungsleitfaden.md`) names a reference configuration for VS-NfD operation, but it is prose: the application cannot answer whether the running configuration matches it, and an operator flipping a switch in the admin UI gets no hint that the choice leaves the profile. Requested by the operator (2026-07-30) as a follow-up to the M24/M25 switches: the application itself should know which options violate the profile — while deployments outside any VS context stay entirely unaffected. ## Decision 1. **A deploy-level mode, not a runtime setting.** `VS_NFD_MODE` (`off | marked | hidden | enforced`) is an environment variable, validated in the shared env schema and passed through compose — for the same reason as `BACKUP_ALLOWED_TARGETS` (#192, ADR 0026): a compromised Site-Admin account must not be able to widen it. The modes escalate: `marked` shows violations at the point of decision (#244), `hidden` removes violating options and marks the hiding (#245), `enforced` additionally rejects violating writes server-side (#246) — hiding alone is UI cosmetics a scripted client bypasses. 2. **`off` is the default.** Outside a VS context the profile is not a topic: no marking, no card, no behavioural difference. Existing deployments upgrade without noticing the feature exists. 3. **The machine-readable catalog is the single source of truth** (`packages/shared/src/vs-nfd-profile.ts`): every profile-relevant setting with a decidable compliant value (a tiny predicate model — equals, upper bound, non-empty) and its hardening-guide section. Judgement-call entries ("only what the service needs") live in an explicit advisory list. A fence test (pattern of the audit-catalogue fence #201) parses the guide's reference tables and fails when a switch is neither in the catalog nor in the advisory list — the guide keeps its binding maintenance rule, the catalog can never silently lag. 4. **Pond-level opt-ins are deliberately absent** (`apiEnabled`, `mcpEnabled`): their instance master switches govern; a pond opt-in under a compliant master switch cannot violate the profile on its own. The evaluation and enforcement paths are scope-generic, so pond entries can be added if that judgement changes. 5. **Exposure first** (#243): the api evaluates the catalog against the typed settings registry and the validated env and reports mode + verdict on `GET /admin/system/vs-nfd-profile`; the admin settings view shows the card whenever the mode is not `off`. The three treatments build on exactly this evaluation. ## Consequences - The guide gains a second consumer: every new switch line must be triaged (catalog or advisory) or CI fails — a deliberate speed bump, same trade-off as the audit-catalogue fence. - Deploy-level means changing the mode requires a deployment change and an api restart; that is the point (role separation, operations handbook §6). - The verdict describes decidable entries only; advisory entries remain an assessor's reading of the guide. The card says what deviates, the guide says why it matters. ## Implementing issues #243 (mode, catalog, fence, exposure), #244 (`marked`), #245 (`hidden`), #246 (`enforced`).