ADR-0046: Housekeeping ships enabled by default (opt-out)
ODD Platform ships data housekeeping on by default — it deletes aged rows out of the box, so bounded DB growth is the default posture and an operator must opt out to keep data indefinitely.
Status
Accepted. Reconstructed from the codebase on 2026-05-30; the decision is live in the source today.
Context
The housekeeping subsystem (ADR-0045) deletes aged data: resolved alerts, search facets, and soft-deleted data entities past a TTL. Every other heavyweight subsystem in the platform — GenAI (ADR-0004), Data Collaboration (ADR-0019), Notifications (ADR-0040) — ships disabled by default, because each needs external configuration to do anything useful. Housekeeping is different in kind: it needs no external system, and the thing it prevents (unbounded table growth on an append-heavy platform) is a problem every deployment has. So the platform had to decide which default serves operators better — off (preserve everything, grow unbounded) or on (bound growth, delete aged data).
Decision
Housekeeping ships enabled by default — it is opt-out, not opt-in. The shipped application.yml sets housekeeping.enabled: true verbatim, and HousekeepingJobManager is gated by @ConditionalOnProperty(value = "housekeeping.enabled", havingValue = "true"). A default deployment therefore runs the cleanup cycle and deletes aged data without any configuration; an operator who wants to keep everything must explicitly set housekeeping.enabled: false.
This is a deliberate divergence from the platform's ship-disabled-by-default family. Those features ship off because they are inert without external wiring; housekeeping ships on because bounded database growth is the platform's default operational posture — leaving it off would let the activity, alert, and search-facet tables grow without limit on every untouched deployment. The default encodes "the platform keeps itself bounded unless you tell it not to."
Consequences
📌 A default deployment deletes data. Out of the box, resolved alerts, search facets, and soft-deleted data entities older than their TTL (each 30 days by default) are removed on the cleanup cycle. This is intended, but an operator who needs indefinite retention (for audit or compliance) must set
housekeeping.enabled: false— and should know the default is delete, not keep.The TTLs are configurable (
housekeeping.ttl.*), so retention windows can be lengthened rather than disabling the subsystem entirely.Because the condition uses
havingValue = "true"with nomatchIfMissing, the shipped-on default applies through the shippedapplication.yml: a deployment that replaces that file without re-supplyinghousekeeping.enabledgets housekeeping off (the absent key fails the condition). The integration-test profile relies on exactly this, settinghousekeeping.enabled: falseto keep test data. Operators templating their own config should carry the key forward deliberately.A contributor proposing to flip housekeeping to disabled-by-default "for consistency" with the other subsystems is working against this decision — the inconsistency is intentional and reflects that housekeeping is an operational-hygiene concern, not a feature integration.
Evidence
odd-platform-api/src/main/resources/application.yml:165-166—housekeeping:/enabled: true(the verbatim shipped default);:167-170— thettlblock (resolved_alerts_days,search_facets_days,data_entity_delete_days, each30).odd-platform-api/.../housekeeping/HousekeepingJobManager.java:17-18—@Component+@ConditionalOnProperty(value = "housekeeping.enabled", havingValue = "true")(nomatchIfMissing): the strict gate that, combined with the shippedtrue, produces opt-out semantics.odd-platform-api/src/test/resources/application-integration-test.yml:8-9—housekeeping:/enabled: false: the test profile opts out, exercising the same toggle and confirming it is the real on/off switch.
See also
ADR-0045 — Housekeeping is a separate subsystem from partition management — what the housekeeping subsystem is and does.
Last updated