Context
This is a narrow child leaf under the B3 production-read cleanup tracked by #12461 and parent Epic #12456. The broad #12461 workstream intentionally wants cluster-sized PRs; current open PR duplicate checks found GitLab (#12526 / PR #12528), ProtoSource (#12504 / PR #12505), and orchestrator (#12515 / PR #12516), but no leaf for the three Knowledge Base daemon helpers.
Current-source evidence on origin/dev:
ai/daemons/kb-alerting/KbAlertingService.mjs:225-235 documents and returns aiConfig.knowledgeBase || {}.
ai/daemons/kb-gc/KbGarbageCollectionService.mjs:264-274 documents and returns aiConfig.knowledgeBase || {}.
ai/daemons/kb-reconciliation/KbReconciliationService.mjs:248-258 documents and returns aiConfig.knowledgeBase || {}.
ai/config.template.mjs:582 declares the knowledgeBase config subtree as the owning source.
Duplicate sweep:
- KB ticket search for
KB daemon knowledgeBase || {} AiConfig B3 defensive reads kb-alerting kb-gc kb-reconciliation found historical KB daemon/config tickets, but no equivalent current B3 cleanup leaf.
- Exact local/GitHub searches for
knowledgeBase || {}, kb-alerting, kb-gc, and kb-reconciliation found #12461 as the parent cluster plus older daemon-location work, but no open leaf covering these three fallbacks.
The Problem
These helpers preserve a stale defensive seam: they convert a missing aiConfig.knowledgeBase subtree into {} and their JSDoc says this protects stale gitignored config.mjs overlays. ADR 0019 classifies this as B3: consumers must read the resolved Provider subtree directly and let SSOT shape failures fail loud.
The stale-overlay concern is real, but it belongs in deploy/bootstrap freshness, not a production consumer fallback. Keeping the fallback makes a broken config tree look like an intentionally-disabled daemon, which weakens the exact fail-loud behavior #12461 is removing.
The Architectural Reality
ADR 0019 is the source of authority: read resolved leaves at the use site; never defend against the AiConfig Provider SSOT. The parent #12461 explicitly calls out the kb-gc / kb-reconciliation / kb-alerting || {} guards as deploy-layer stale-config.mjs concerns, not code-side fallbacks.
The three helper methods are a coherent one-PR cluster because they share the same shape:
- helper JSDoc says the config overlay can lack
knowledgeBase;
- helper returns
aiConfig.knowledgeBase || {};
- daemon startup behavior then treats missing config as disabled/empty rather than surfacing the malformed SSOT.
The Fix
Update the three KB daemon services to read aiConfig.knowledgeBase directly through their existing test-stubbable helper methods. Remove or rewrite JSDoc that describes stale config.mjs overlays as a supported code-side fallback. Keep each daemon's existing opt-in semantics and per-leaf fallback constants; this ticket only removes the subtree fallback.
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
KbAlertingService.getKnowledgeBaseConfig() |
ai/daemons/kb-alerting/KbAlertingService.mjs; ai/config.template.mjs knowledgeBase subtree; ADR 0019 |
Return aiConfig.knowledgeBase directly. |
None in consumer; deploy/bootstrap must refresh stale overlays. |
Helper JSDoc no longer claims missing subtree is tolerated. |
Static guard proves no `aiConfig.knowledgeBase |
KbGarbageCollectionService.getKnowledgeBaseConfig() |
ai/daemons/kb-gc/KbGarbageCollectionService.mjs; ai/config.template.mjs knowledgeBase subtree; ADR 0019 |
Return aiConfig.knowledgeBase directly. |
None in consumer; deploy/bootstrap must refresh stale overlays. |
Helper JSDoc no longer claims missing subtree is tolerated. |
Static guard proves no `aiConfig.knowledgeBase |
KbReconciliationService.getKnowledgeBaseConfig() |
ai/daemons/kb-reconciliation/KbReconciliationService.mjs; ai/config.template.mjs knowledgeBase subtree; ADR 0019 |
Return aiConfig.knowledgeBase directly. |
None in consumer; deploy/bootstrap must refresh stale overlays. |
Helper JSDoc no longer claims missing subtree is tolerated. |
Static guard proves no `aiConfig.knowledgeBase |
Decision Record impact
aligned-with ADR 0019 (AiConfig reactive Provider SSOT).
Acceptance Criteria
Out of Scope
- Other B3 clusters under #12461, including memory-core, KB ingestion/vector, graph/ingestion, maintenance scripts, and examples.
- Deploy/bootstrap remediation for stale gitignored
config.mjs overlays; this ticket only removes the production consumer fallback.
- Changing the daemon scheduling, alerting, garbage-collection, or reconciliation contracts beyond the subtree read.
- Test-side B3/B4 cleanup.
Avoided Traps
- Do not replace
|| {} with optional chaining or another local default object; that preserves the same B3 shape.
- Do not move
knowledgeBase defaults into the daemons; the config leaf/subtree owns defaults and environment binding.
- Do not broaden this PR to every remaining #12461 match; the point is a small three-file daemon cluster.
Related
Parent B3 workstream: #12461
Parent Epic: #12456
Sibling leaves: #12504, #12515, #12526
Authority: ADR 0019 (learn/agentos/decisions/0019-aiconfig-reactive-provider-ssot.md)
Origin Session ID: dcdaac0b-9ae0-45b5-b4da-da39541af497
Handoff Retrieval Hint: query_raw_memories("KB daemon knowledgeBase fallback AiConfig B3 kb-alerting kb-gc kb-reconciliation") or search current source for aiConfig.knowledgeBase || {}.
Context
This is a narrow child leaf under the B3 production-read cleanup tracked by #12461 and parent Epic #12456. The broad #12461 workstream intentionally wants cluster-sized PRs; current open PR duplicate checks found GitLab (#12526 / PR #12528), ProtoSource (#12504 / PR #12505), and orchestrator (#12515 / PR #12516), but no leaf for the three Knowledge Base daemon helpers.
Current-source evidence on
origin/dev:ai/daemons/kb-alerting/KbAlertingService.mjs:225-235documents and returnsaiConfig.knowledgeBase || {}.ai/daemons/kb-gc/KbGarbageCollectionService.mjs:264-274documents and returnsaiConfig.knowledgeBase || {}.ai/daemons/kb-reconciliation/KbReconciliationService.mjs:248-258documents and returnsaiConfig.knowledgeBase || {}.ai/config.template.mjs:582declares theknowledgeBaseconfig subtree as the owning source.Duplicate sweep:
KB daemon knowledgeBase || {} AiConfig B3 defensive reads kb-alerting kb-gc kb-reconciliationfound historical KB daemon/config tickets, but no equivalent current B3 cleanup leaf.knowledgeBase || {},kb-alerting,kb-gc, andkb-reconciliationfound #12461 as the parent cluster plus older daemon-location work, but no open leaf covering these three fallbacks.The Problem
These helpers preserve a stale defensive seam: they convert a missing
aiConfig.knowledgeBasesubtree into{}and their JSDoc says this protects stale gitignoredconfig.mjsoverlays. ADR 0019 classifies this as B3: consumers must read the resolved Provider subtree directly and let SSOT shape failures fail loud.The stale-overlay concern is real, but it belongs in deploy/bootstrap freshness, not a production consumer fallback. Keeping the fallback makes a broken config tree look like an intentionally-disabled daemon, which weakens the exact fail-loud behavior #12461 is removing.
The Architectural Reality
ADR 0019 is the source of authority: read resolved leaves at the use site; never defend against the AiConfig Provider SSOT. The parent #12461 explicitly calls out the
kb-gc/kb-reconciliation/kb-alerting|| {}guards as deploy-layer stale-config.mjsconcerns, not code-side fallbacks.The three helper methods are a coherent one-PR cluster because they share the same shape:
knowledgeBase;aiConfig.knowledgeBase || {};The Fix
Update the three KB daemon services to read
aiConfig.knowledgeBasedirectly through their existing test-stubbable helper methods. Remove or rewrite JSDoc that describes staleconfig.mjsoverlays as a supported code-side fallback. Keep each daemon's existing opt-in semantics and per-leaf fallback constants; this ticket only removes the subtree fallback.Contract Ledger Matrix
KbAlertingService.getKnowledgeBaseConfig()ai/daemons/kb-alerting/KbAlertingService.mjs;ai/config.template.mjsknowledgeBasesubtree; ADR 0019aiConfig.knowledgeBasedirectly.KbGarbageCollectionService.getKnowledgeBaseConfig()ai/daemons/kb-gc/KbGarbageCollectionService.mjs;ai/config.template.mjsknowledgeBasesubtree; ADR 0019aiConfig.knowledgeBasedirectly.KbReconciliationService.getKnowledgeBaseConfig()ai/daemons/kb-reconciliation/KbReconciliationService.mjs;ai/config.template.mjsknowledgeBasesubtree; ADR 0019aiConfig.knowledgeBasedirectly.Decision Record impact
aligned-with ADR 0019 (AiConfig reactive Provider SSOT).
Acceptance Criteria
ai/daemons/kb-alerting/KbAlertingService.mjscontains noaiConfig.knowledgeBase || {}fallback and readsaiConfig.knowledgeBasedirectly.ai/daemons/kb-gc/KbGarbageCollectionService.mjscontains noaiConfig.knowledgeBase || {}fallback and readsaiConfig.knowledgeBasedirectly.ai/daemons/kb-reconciliation/KbReconciliationService.mjscontains noaiConfig.knowledgeBase || {}fallback and readsaiConfig.knowledgeBasedirectly.config.mjsas a consumer-side fallback.knowledgeBasesubtree exists with disabled leaves.Out of Scope
config.mjsoverlays; this ticket only removes the production consumer fallback.Avoided Traps
|| {}with optional chaining or another local default object; that preserves the same B3 shape.knowledgeBasedefaults into the daemons; the config leaf/subtree owns defaults and environment binding.Related
Parent B3 workstream: #12461 Parent Epic: #12456 Sibling leaves: #12504, #12515, #12526 Authority: ADR 0019 (
learn/agentos/decisions/0019-aiconfig-reactive-provider-ssot.md)Origin Session ID: dcdaac0b-9ae0-45b5-b4da-da39541af497
Handoff Retrieval Hint:
query_raw_memories("KB daemon knowledgeBase fallback AiConfig B3 kb-alerting kb-gc kb-reconciliation")or search current source foraiConfig.knowledgeBase || {}.