The tenant-repo deployment snapshot added by closed #14396 can report enablement, task state, effective repo counts, config tiers, revisions, and bounded failure codes. Its config projection is only as honest as the upstream resolver, however.
A fresh executable probe against current dev produced the same value for three materially different bootstrap states:
The public source tree also contains a liveness empirical-anchor comment whose operational facts are useful but whose suffix names a specific organization/incident. Public Neo source must keep customer and deployment identities generic.
Live latest-open sweep: checked the latest 20 open issues at 2026-07-23T10:14:19Z; no equivalent found. Targeted live search for tenant-repo bootstrap, malformed kb-config, and diagnostics found only closed predecessor #14404. A2A all-state sweep: checked the latest 30 messages inside the 60-minute herd window; no overlapping earlier claim found.
The Problem
KnowledgeBaseIngestionService.readKbConfigBootstrap() catches every failure and returns null for an absent file, an unreadable file, malformed YAML, and an empty document (ai/services/knowledge-base/IngestionService.mjs:1292-1314). That fail-soft behavior preserves fallback resolution, but it destroys the provenance needed for cloud diagnosis.
listConfiguredTenantRepos() consumes only the nullable document (IngestionService.mjs:1317-1344). TenantRepoSyncService.resolveTenantReposConfig() forwards the flattened result, and DeploymentStateBridgeService.collectTenantRepoSyncSnapshot() can therefore summarize only the repos it received. When resolution does not throw, summarizeTenantRepoConfig() reports status: available and a count—even when the YAML bootstrap was unreadable or malformed (ai/daemons/orchestrator/services/DeploymentStateBridgeService.mjs:608-623,836-855).
This collapses distinct operator actions:
missing optional bootstrap: confirm another config tier or mount the file if it was intended;
valid empty bootstrap: configuration was read successfully and declares no YAML tenants/repos;
unreadable bootstrap: fix mount ownership/permissions;
malformed YAML: fix syntax;
invalid top-level shape: fix the deployment contract.
Separately, ai/services/graph/ollamaStuckRunnerLiveness.mjs:8-9 embeds a named-customer suffix in a tracked public comment. The model, CPU, and duration measurements are a valid generic empirical anchor; the organization identity is not.
The Architectural Reality
kb-config.yaml is an optional Tier-2 bootstrap. The graph tier remains canonical and the AiConfig provider remains the fallback.
Fail-soft fallback and fail-honest diagnostics are compatible: runtime config resolution may continue while a structured diagnostic records what happened.
DeploymentStateBridgeService already owns the redacted public snapshot and already distinguishes thrown config reads from valid empty results. It needs structured bootstrap provenance from the resolver rather than filesystem access of its own.
AiConfig remains the reactive Provider SSOT per ADR 0019. This work reads AiConfig.neoRootDir at the existing use site; it must not add env re-resolution, pass-along config plumbing, defensive optional chaining, or runtime mutation.
ollamaStuckRunnerLiveness.mjs owns the liveness classifier and its explanatory JSDoc. Scrubbing the identity changes no runtime behavior.
Structure-map ownership: changes stay within existing ai/services/knowledge-base, ai/daemons/orchestrator/services, and ai/services/graph siblings. No new service, daemon, or directory is required.
The Fix
Add a structured bootstrap-read result at the existing Knowledge Base service boundary, for example readKbConfigBootstrapResult():
status: missing, empty, loaded, read-failed, parse-failed, or invalid-shape;
document: parsed object only for valid input, otherwise null;
bounded errorCode and messageClass for failures;
no absolute host path, YAML content, tenant/repo names, clone URLs, credential references, tokens, stack, or raw filesystem message.
Preserve compatibility by keeping readKbConfigBootstrap() as the document-only consumer path (delegating to the structured result), or migrate all internal callers atomically without changing config-tier precedence.
Extend listConfiguredTenantRepos() to return redacted configDiagnostics.bootstrap alongside tenantRepos.
Project that data through TenantRepoSyncService.resolveTenantReposConfig() into tenantRepoSync.config.bootstrap:
missing and valid empty remain non-error states;
read-failed, parse-failed, and invalid-shape make the config diagnostic degraded while still showing any safely resolved fallback repos;
repo work may continue from a valid higher/fallback tier, but the bootstrap failure must not disappear.
Update cloud configuration/troubleshooting docs with the state/action mapping.
Replace the named-organization suffix in the Ollama stuck-runner empirical-anchor comment with generic cloud-deployment wording while retaining the useful model/CPU/duration evidence.
Contract Ledger Matrix
Target Surface
Source of Authority
Proposed Behavior
Fallback / Edge Case
Docs
Evidence
New structured bootstrap-read result in KnowledgeBaseIngestionService
Current readKbConfigBootstrap() behavior + this ticket
Return a bounded status, document, and categorical failure metadata
Missing/empty return no error; read/parse/shape failures return no document and never leak raw input/path/message
JSDoc on the loader
Unit tests for every status and redaction
Existing readKbConfigBootstrap() document path
Current IngestionService.mjs config-tier contract
Preserve object-or-null compatibility for existing resolution callers
Delegates to the structured loader; fallback precedence remains graph > YAML > AiConfig
Existing resolver JSDoc
Existing tier-precedence suite remains green
listConfiguredTenantRepos() result
Current resolver consumed by TenantRepoSyncService
Distinguish missing, valid-empty, loaded, read-failed, parse-failed, and invalid-shape states
Failure degrades config diagnostics without hiding safely resolved fallback repo counts; output remains bounded and secret-free
Cloud troubleshooting and KB diagnostic docs
Snapshot tests for each state and explicit redaction assertions
Ollama stuck-runner empirical-anchor comment
Public-artifact client-neutrality invariant
Preserve generic operational measurements without identifying an organization or private incident
Use generic cloud-deployment wording; no runtime change
JSDoc only
Static source assertion/review plus tracked-tree identity scan
Decision Record impact
Aligned with ADR 0014's cloud deployment topology and ADR 0019's AiConfig Provider SSOT. No ADR amendment: this improves observability at existing boundaries without changing tier precedence, runtime topology, or config authority.
Acceptance Criteria
Bootstrap diagnostics distinguish missing, empty, loaded, read-failed, parse-failed, and invalid-shape.
A missing optional YAML file does not degrade a deployment that resolves through another valid tier, but its absence remains visible.
Read, parse, and shape failures are visible as degraded config diagnostics even when fallback repos can still be enumerated.
tenantRepoSync.config.bootstrap exposes only status, bounded stable code/message class, and non-sensitive counts; it excludes absolute paths, raw YAML, tenant/repo identities, clone URLs, credential references, tokens, stacks, and raw OS messages.
Context
The tenant-repo deployment snapshot added by closed
#14396can report enablement, task state, effective repo counts, config tiers, revisions, and bounded failure codes. Its config projection is only as honest as the upstream resolver, however.A fresh executable probe against current
devproduced the same value for three materially different bootstrap states:{ "missing": null, "malformed": null, "unreadable": null }The public source tree also contains a liveness empirical-anchor comment whose operational facts are useful but whose suffix names a specific organization/incident. Public Neo source must keep customer and deployment identities generic.
Live latest-open sweep: checked the latest 20 open issues at 2026-07-23T10:14:19Z; no equivalent found. Targeted live search for tenant-repo bootstrap, malformed
kb-config, and diagnostics found only closed predecessor#14404. A2A all-state sweep: checked the latest 30 messages inside the 60-minute herd window; no overlapping earlier claim found.The Problem
KnowledgeBaseIngestionService.readKbConfigBootstrap()catches every failure and returnsnullfor an absent file, an unreadable file, malformed YAML, and an empty document (ai/services/knowledge-base/IngestionService.mjs:1292-1314). That fail-soft behavior preserves fallback resolution, but it destroys the provenance needed for cloud diagnosis.listConfiguredTenantRepos()consumes only the nullable document (IngestionService.mjs:1317-1344).TenantRepoSyncService.resolveTenantReposConfig()forwards the flattened result, andDeploymentStateBridgeService.collectTenantRepoSyncSnapshot()can therefore summarize only the repos it received. When resolution does not throw,summarizeTenantRepoConfig()reportsstatus: availableand a count—even when the YAML bootstrap was unreadable or malformed (ai/daemons/orchestrator/services/DeploymentStateBridgeService.mjs:608-623,836-855).This collapses distinct operator actions:
Separately,
ai/services/graph/ollamaStuckRunnerLiveness.mjs:8-9embeds a named-customer suffix in a tracked public comment. The model, CPU, and duration measurements are a valid generic empirical anchor; the organization identity is not.The Architectural Reality
kb-config.yamlis an optional Tier-2 bootstrap. The graph tier remains canonical and the AiConfig provider remains the fallback.DeploymentStateBridgeServicealready owns the redacted public snapshot and already distinguishes thrown config reads from valid empty results. It needs structured bootstrap provenance from the resolver rather than filesystem access of its own.AiConfigremains the reactive Provider SSOT per ADR 0019. This work readsAiConfig.neoRootDirat the existing use site; it must not add env re-resolution, pass-along config plumbing, defensive optional chaining, or runtime mutation.ollamaStuckRunnerLiveness.mjsowns the liveness classifier and its explanatory JSDoc. Scrubbing the identity changes no runtime behavior.Structure-map ownership: changes stay within existing
ai/services/knowledge-base,ai/daemons/orchestrator/services, andai/services/graphsiblings. No new service, daemon, or directory is required.The Fix
readKbConfigBootstrapResult():status:missing,empty,loaded,read-failed,parse-failed, orinvalid-shape;document: parsed object only for valid input, otherwisenull;errorCodeandmessageClassfor failures;readKbConfigBootstrap()as the document-only consumer path (delegating to the structured result), or migrate all internal callers atomically without changing config-tier precedence.listConfiguredTenantRepos()to return redactedconfigDiagnostics.bootstrapalongsidetenantRepos.TenantRepoSyncService.resolveTenantReposConfig()intotenantRepoSync.config.bootstrap:missingand validemptyremain non-error states;read-failed,parse-failed, andinvalid-shapemake the config diagnostic degraded while still showing any safely resolved fallback repos;Contract Ledger Matrix
KnowledgeBaseIngestionServicereadKbConfigBootstrap()behavior + this ticketreadKbConfigBootstrap()document pathIngestionService.mjsconfig-tier contractlistConfiguredTenantRepos()resultTenantRepoSyncServiceconfigDiagnostics.bootstrapbesidetenantRepostenantReposremain compatibletenantRepoSync.config.bootstrapdeployment snapshot field#14396diagnostic contract +DeploymentStateBridgeServiceDecision Record impact
Aligned with ADR 0014's cloud deployment topology and ADR 0019's AiConfig Provider SSOT. No ADR amendment: this improves observability at existing boundaries without changing tier precedence, runtime topology, or config authority.
Acceptance Criteria
missing,empty,loaded,read-failed,parse-failed, andinvalid-shape.tenantRepoSync.config.bootstrapexposes only status, bounded stable code/message class, and non-sensitive counts; it excludes absolute paths, raw YAML, tenant/repo identities, clone URLs, credential references, tokens, stacks, and raw OS messages.Out of Scope
#15748.Avoided Traps
DeploymentStateBridgeService; the Knowledge Base resolver owns bootstrap interpretation.Related
Related: #14396
Related: #14404
Related: #15748
Origin Session ID: fc1a49c1-e30a-4e3a-960a-e0596367a4c1
Handoff Retrieval Hint:
kb-config bootstrap missing malformed unreadable tenantRepoSync config diagnostics client-neutral liveness comment