Context
This is a narrow child leaf under the B3 production-read cleanup tracked by #12461 and parent Epic #12456. The broad #12461 ticket is valid as the B3 workstream, but it is intentionally cluster-shaped: one PR per source cluster. Current duplicate checks found active leaves for ProtoSource (#12504 / PR #12505) and orchestrator (#12515 / PR #12516), but no GitLab workflow leaf.
Observed current-source evidence on dev:
ai/services/gitlab-workflow/HealthService.mjs imports ai/mcp/server/gitlab-workflow/config.mjs as aiConfig.
HealthService.healthcheck() reads aiConfig.gitlab?.hostUrl || '' and aiConfig.gitlab?.token.
ai/mcp/server/gitlab-workflow/config.template.mjs declares resolved leaves for gitlab.hostUrl (NEO_GITLAB_HOST, default https://gitlab.com) and gitlab.token (NEO_GITLAB_PAT, default empty string).
The Problem
ADR 0019 classifies defensive reads around the AiConfig Provider SSOT as B3. Optional chaining on the guaranteed gitlab subtree masks a broken config tree instead of failing loud. The || '' hidden default also re-states a leaf default at the consumer instead of letting the leaf own the default.
For this service, that means the healthcheck can quietly convert a malformed/missing gitlab subtree into an empty host URL and then report a generic missing-host detail, rather than surfacing the actual SSOT violation.
The Architectural Reality
ADR 0019 is the source of authority: read resolved leaves at the use site; never defend against the SSOT. The GitLab workflow config already owns these leaves:
| Surface |
Source of authority |
Current defensive read |
Sanctioned read |
gitlab.hostUrl |
ai/mcp/server/gitlab-workflow/config.template.mjs leaf hostUrl: leaf('https://gitlab.com', 'NEO_GITLAB_HOST', 'url') |
`aiConfig.gitlab?.hostUrl |
|
gitlab.token |
ai/mcp/server/gitlab-workflow/config.template.mjs leaf token: leaf('', 'NEO_GITLAB_PAT', 'string') |
aiConfig.gitlab?.token |
aiConfig.gitlab.token |
The Fix
Update ai/services/gitlab-workflow/HealthService.mjs to read the resolved leaves directly:
- replace
aiConfig.gitlab?.hostUrl || '' with aiConfig.gitlab.hostUrl;
- replace
aiConfig.gitlab?.token with aiConfig.gitlab.token.
Keep the existing healthcheck behavior that reports a missing host when the resolved leaf is empty; the cleanup is about SSOT fail-loud semantics, not changing the public healthcheck payload shape.
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
HealthService.healthcheck().gitlab.hostUrl |
ai/services/gitlab-workflow/HealthService.mjs; ai/mcp/server/gitlab-workflow/config.template.mjs gitlab.hostUrl leaf; ADR 0019 |
Report the resolved aiConfig.gitlab.hostUrl leaf value. |
None in consumer; leaf default/env binding owns fallback. |
Existing class JSDoc stays accurate. |
Unit/static coverage should verify no gitlab?.hostUrl or consumer-side ` |
HealthService.healthcheck().gitlab.tokenConfigured |
ai/services/gitlab-workflow/HealthService.mjs; ai/mcp/server/gitlab-workflow/config.template.mjs gitlab.token leaf; ADR 0019 |
Derive Boolean from resolved aiConfig.gitlab.token. |
None in consumer; leaf default/env binding owns fallback. |
Existing class JSDoc stays accurate. |
Unit/static coverage should verify no gitlab?.token remains. |
Decision Record impact
aligned-with ADR 0019 (AiConfig reactive Provider SSOT).
Acceptance Criteria
Out of Scope
- Other B3 clusters under #12461 (memory-core, knowledge-base, graph/ingestion, maintenance, examples).
- B4 test singleton writes (#12435).
- The SSOT lint (#12451).
- GitLab API connectivity or GitLab client implementation.
Avoided Traps
- Do not add a helper or local alias for
gitlab; direct leaf reads are the point.
- Do not move the GitLab host/token defaults into
HealthService; the leaf declaration already owns defaults and env binding.
- Do not broaden this PR to unrelated B3 clusters; #12461 explicitly wants cluster-sized PRs.
Related
Parent B3 workstream: #12461
Parent Epic: #12456
Sibling leaves: #12504, #12515
Authority: ADR 0019 (learn/agentos/decisions/0019-aiconfig-reactive-provider-ssot.md)
Origin Session ID: dcdaac0b-9ae0-45b5-b4da-da39541af497
Retrieval Hint: query_raw_memories("GitLab workflow B3 AiConfig defensive reads HealthService") or search current source for aiConfig.gitlab?..
Context
This is a narrow child leaf under the B3 production-read cleanup tracked by #12461 and parent Epic #12456. The broad #12461 ticket is valid as the B3 workstream, but it is intentionally cluster-shaped: one PR per source cluster. Current duplicate checks found active leaves for ProtoSource (#12504 / PR #12505) and orchestrator (#12515 / PR #12516), but no GitLab workflow leaf.
Observed current-source evidence on
dev:ai/services/gitlab-workflow/HealthService.mjsimportsai/mcp/server/gitlab-workflow/config.mjsasaiConfig.HealthService.healthcheck()readsaiConfig.gitlab?.hostUrl || ''andaiConfig.gitlab?.token.ai/mcp/server/gitlab-workflow/config.template.mjsdeclares resolved leaves forgitlab.hostUrl(NEO_GITLAB_HOST, defaulthttps://gitlab.com) andgitlab.token(NEO_GITLAB_PAT, default empty string).The Problem
ADR 0019 classifies defensive reads around the AiConfig Provider SSOT as B3. Optional chaining on the guaranteed
gitlabsubtree masks a broken config tree instead of failing loud. The|| ''hidden default also re-states a leaf default at the consumer instead of letting the leaf own the default.For this service, that means the healthcheck can quietly convert a malformed/missing
gitlabsubtree into an empty host URL and then report a generic missing-host detail, rather than surfacing the actual SSOT violation.The Architectural Reality
ADR 0019 is the source of authority: read resolved leaves at the use site; never defend against the SSOT. The GitLab workflow config already owns these leaves:
gitlab.hostUrlai/mcp/server/gitlab-workflow/config.template.mjsleafhostUrl: leaf('https://gitlab.com', 'NEO_GITLAB_HOST', 'url')gitlab.tokenai/mcp/server/gitlab-workflow/config.template.mjsleaftoken: leaf('', 'NEO_GITLAB_PAT', 'string')aiConfig.gitlab?.tokenaiConfig.gitlab.tokenThe Fix
Update
ai/services/gitlab-workflow/HealthService.mjsto read the resolved leaves directly:aiConfig.gitlab?.hostUrl || ''withaiConfig.gitlab.hostUrl;aiConfig.gitlab?.tokenwithaiConfig.gitlab.token.Keep the existing healthcheck behavior that reports a missing host when the resolved leaf is empty; the cleanup is about SSOT fail-loud semantics, not changing the public healthcheck payload shape.
Contract Ledger Matrix
HealthService.healthcheck().gitlab.hostUrlai/services/gitlab-workflow/HealthService.mjs;ai/mcp/server/gitlab-workflow/config.template.mjsgitlab.hostUrlleaf; ADR 0019aiConfig.gitlab.hostUrlleaf value.gitlab?.hostUrlor consumer-side `HealthService.healthcheck().gitlab.tokenConfiguredai/services/gitlab-workflow/HealthService.mjs;ai/mcp/server/gitlab-workflow/config.template.mjsgitlab.tokenleaf; ADR 0019aiConfig.gitlab.token.gitlab?.tokenremains.Decision Record impact
aligned-with ADR 0019 (AiConfig reactive Provider SSOT).
Acceptance Criteria
ai/services/gitlab-workflow/HealthService.mjscontains zeroaiConfig.gitlab?.reads.HealthService.healthcheck()readsaiConfig.gitlab.hostUrlandaiConfig.gitlab.tokendirectly.|| '') remains forgitlab.hostUrl; the config leaf owns the default.Out of Scope
Avoided Traps
gitlab; direct leaf reads are the point.HealthService; the leaf declaration already owns defaults and env binding.Related
Parent B3 workstream: #12461 Parent Epic: #12456 Sibling leaves: #12504, #12515 Authority: ADR 0019 (
learn/agentos/decisions/0019-aiconfig-reactive-provider-ssot.md)Origin Session ID: dcdaac0b-9ae0-45b5-b4da-da39541af497
Retrieval Hint:
query_raw_memories("GitLab workflow B3 AiConfig defensive reads HealthService")or search current source foraiConfig.gitlab?..