Repository navigation
inventory(canonical): 19 concepts with more than one definition and no existing issue — led by two secret stores whose docstrings each claim they cannot disagree about the key #17856
Description
Child of #13916.
What this is
An inventory, not a defect report. Each row is a concept with more than one definition, found during a duplicate-definition sweep, checked against open and closed issues, and confirmed to have no existing home. They are recorded together so the set is finite and nothing is lost; they are not claimed to share one fix.
Everything already filed elsewhere was excluded: #14776/#14774 (kit adoption), #14785 (CSS tokens), #17419 (env planes), #14590 (dead infra units), #17441 (Redis TLS renderers), #14130 (chroma unit directives), #16253 (SystemStatusDetails), #13138 (SLM hand-typed types), #10088 (secret stores), #12363/#12420/#14062 (frontend contract), #17848, #17849, #17852, #17853, #17854, #17855.
Leading row
SecretsManager and SecretsService read different key sources, while both docstrings claim they can never disagree about the key.
autobot-backend/api/secrets.py:185-193— Fernet over the key filesecrets.key, ciphertext stored asbase64(fernet-token)insecrets.json. It reads only the key file and never consultsAUTOBOT_SECRETS_KEY.autobot-backend/services/secrets_service.py:90-115,158-165— Fernet over SQLite, raw token with no base64 wrap. Key priority: explicit argument, thenconfig.secrets_key(AUTOBOT_SECRETS_KEY), then config-managersecurity.secrets_key, then the shared key file.
So if AUTOBOT_SECRETS_KEY is set, the two stores use different keys while each docstring asserts they cannot. The ciphertext encodings also differ, which services/json_secrets_importer.py:80 has to know about explicitly. Callers of the first: initialization/lifespan.py:347, slash_command_handler.py:933, api/infrastructure.py:35, api/nl_database.py:67, api/codebase_analytics/endpoints/sources.py:54. Callers of the second: llm_shared/run_credential_loader.py:21, llm_shared/providers/bedrock_credentials.py:35, knowledge/connectors/credential_store.py:763, services/workflow_secret_service.py:20, services/agent_secrets_integration.py:23. The canonical target per #10088 is the envelope vault, which is neither of these.
The rest
| Concept | Definitions | Note |
|---|---|---|
backend_workers |
roles/backend/defaults/main.yml:39 = 4 ("dedicated backend VMs keep 4"); playbooks/vars/backend-env.yml:18 = 1, pulled in by include_vars at playbooks/update-all-nodes.yml:1110 |
A dedicated VM is deployed with 4 workers and silently drops to 1 on the next update, re-rendered by roles/backend/tasks/unit_only.yml. Contradicts comments in both files. #876's co-located workaround leaks to every host |
ai_stack_port |
8080 in inventory/production.yml:49,204, group_vars/aiml.yml:66 and setup-user-backend.yml:58; 11434 in roles/distributed_setup/defaults/main.yml:72 and fix-slm-env-ports.yml:30 |
11434 is the Ollama port. fix-slm-env-ports.yml's own header (lines 9-10) asserts "AI Stack / Ollama: port 11434 (not 8080)", contradicting the inventory and the service, which listens on 8080. Written to AUTOBOT_AI_STACK_PORT, AUTOBOT_AI_STACK_URL and VITE_AI_STACK_PORT |
| NPU worker port | 8081 in npu_inference_server.py:224 and npu_worker_main.py:106; 8080 in autobot-backend/cli/doctor.py:177 |
8080 is the AI-stack port in the SSOT. Same env name also splits bind-vs-connect semantics: doctor.py:176 uses localhost, the workers bind all interfaces |
autobot-backend-single-worker.service.j2 |
ansible/templates/ versus the canonical roles/backend/templates/autobot-backend.service.j2 |
Used by fix-backend-worker-deadlock.yml:50 (#876, a manual playbook the role's own comments call legacy). Running it overwrites the canonical unit with a copy that hardcodes --host 0.0.0.0 --port 8443 --workers 1 and drops ExecStartPre=startup_validation.py, LimitNOFILE, MemoryHigh/MemoryMax, KillMode=mixed, TimeoutStartSec and PYTHONFAULTHANDLER. The next role run restores it; nothing keeps the two in step |
VITE_API_TIMEOUT |
60000 (autobot-frontend/src/config/ssot-config.ts:450, root .env.example:472); 30000 (AppConfig.js:136,148, autobot-frontend/.env.example:13); Python AUTOBOT_API_TIMEOUT = 10000 (ssot_config.py:700) |
One VITE key with two frontend defaults and a third value on the Python side. defaults.js:108 consumes the 60000 path |
config/routes.ts |
autobot-frontend/src/config/routes.ts (182 lines, routeConfig) alongside router/index.ts and config/navItems.ts |
Zero importers — referenced only inside its own file. 10 of its 19 paths do not exist in the router (e.g. /knowledge/health, /knowledge/manage, /monitoring/system, /tools/files). navItems.ts is the live registry and is guarded by __tests__/nav-items-coverage.test.ts against the router; this third list has no guard and has drifted. Per the never-delete rule, wiring-in or removal is a decision, not a sweep |
| Auth token readers | main app: utils/authToken.ts:41, utils/fetchWithAuth.ts:20, utils/ApiClient.ts:217, composables/useServiceDiscovery.ts:45, stores/useUserStore.ts:288, config/ssot-config.ts:822. SLM: utils/ApiClient.ts:113, composables/useAutobotApi.ts:673, stores/auth.ts:258 |
Divergent storage: the main app uses one persisted shape (autobot_auth); SLM uses two different keys (slm_access_token and autobot_access_token). The legacy-marker rejection and the expiry check exist only in the main app's ApiClient path |
| Deprecated cache manager still imported | autobot-backend/api/system.py:765,874 import cache_manager from utils/cache_manager (marked deprecated/"Archived") inside the stats endpoints, shadowing the module-level import of advanced_cache_manager at :45 |
Both use the cache: prefix so the reported numbers likely agree today, but the two code paths differ and the shadowing is invisible at the call site |
WorkflowMemory |
autobot_shared/workflow_memory.py (async, key autobot:workflow:{id}:memory, no production importer — test only) versus autobot-backend/orchestration/workflow_memory.py:61 (sync, key workflow:memory:<id>, used by orchestration/workflow_executor.py:97) |
Same name, different Redis key namespaces. An agent using one cannot see data written by the other |
| Duplicate SLM endpoints | get_fleet_services at api/services.py:907 (/fleet/services) and api/orchestration.py:618 (/orchestration/fleet/services), 0.96 similar, both routers mounted. Also api/blue_green.py vs api/deployments.py (list_deployments, get_deployment, create_deployment, 0.75–0.93, both mounted at main.py:674-675), and _create_node_event identical in api/nodes.py:103 and api/updates.py:68 across 12 call sites |
|
_emit_deletion_audit |
tasks/knowledge_retention.py:34, tasks/file_retention.py:31, tasks/chat_retention.py:71 (0.90–0.93) |
Three copies of one audit emission for three retention jobs |
verify_internal_api_key / RS256 denylist prefix |
auth_middleware.py:949 (reads ssot_config.misc.internal_api_key) vs autobot-slm-backend/services/auth.py:316 (reads os.getenv("AUTOBOT_INTERNAL_API_KEY")); and the literal "auth:rs256:jti:denylist:" in services/rs256_revocation.py:39 and autobot-slm-backend/services/rs256_denylist.py:56 |
Both use compare_digest, and the SLM docstring says it "mirrors" the backend. The denylist prefix carries a "MUST match" comment on both sides and lives in neither autobot_shared |
device_token_service |
services/device_jwt.py:128,272 (aud claim, scope validation, DB revocation check, audit; used by auth_middleware.py:705,1029, api/mobile_devices.py:221) versus services/device_token_service.py:26,59 (no aud, no revocation, ISO-string iat) |
The second has no production caller and is strictly weaker. Wiring-in or removal is a decision |
utils/hardware_metrics.py |
Duplicates GPUMetrics, NPUMetrics, MultiModalMetrics, SystemPerformanceMetrics, ServicePerformanceMetrics, _store_performance_in_redis and monitor_performance from utils/performance_monitoring/ |
1,478 lines, no importer anywhere. The performance_monitoring package is live |
is_feature_enabled |
autobot_shared/feature_flags.py:90 (raises on an unknown flag), config/__init__.py:320 (yaml dot-path <feature>.enabled), user_management/config.py:200 (deployment-mode object) |
Three different semantics behind one name |
| Project-root resolution | Canonical autobot_shared/paths.py:109,149; plus api/codebase_analytics/endpoints/shared.py:259 (parents[4], no callers) and :269 (zero-arg .git walk, used by 4 modules); plus workers/audit_tasks.py:255 _repo_root |
|
_sha256_file |
autobot_shared/integrity_manifest.py:55, autobot_shared/pinned_model_registry.py:150, and the npu-worker copy |
The npu-worker copy is a documented standalone (excluded); the two in autobot_shared are not |
| Unverified JWT payload decoders | a2a/peer_identity.py:102 _decode_jwt_sub (pads with + "=="), llm_shared/provider_auth.py:551 _decode_jwt_claims (correct padding, returns all claims) |
Two base64-decode-the-payload helpers. JWT verification itself is well consolidated in autobot_shared/auth/jwt_core.py — no raw jwt.decode exists outside it |
Acceptance criteria
- Each row gets a disposition: adopt one authority, record an exception with its reason, or wire in / retire the unreachable copy with evidence that the work landed. No row is closed by silence.
- The leading row is resolved first and its two docstrings are corrected, since both currently assert a property the code does not have.
- Rows describing a duplicate endpoint (
get_fleet_services, blue-green vs deployments) get a decision on which path is public, since both are mounted today. - Nothing here is deleted on the strength of "no importer found" alone — static-import absence is not proof of unreachability, and dynamic loaders exist in this repo.
Activity
mrveiss commentedon Oct 10, 2026
Triage of all 19 rows against
main@ 7139a85. Every duplication is still present; none is already resolved.Fixing now, with zero behaviour change, on one branch:
_emit_deletion_audit×3;_create_node_event(SLMnodes/updates);Already homed: row 4 (NPU worker port) → #18094; row 17 (project-root resolution) → #18101. Waiting on another branch: row 18
_sha256_file, after the model-revision-pinning branch lands.Decisions needed (owner). Each changes visible behaviour. Recommendations in brackets:
SecretsManager) vs env-first (SecretsService)AUTOBOT_SECRETS_KEYis set in any deployment is not determined]backend_workers4 (role default) vs 1 (playbooks/vars/backend-env.yml, whoseinclude_varsoverrides it on every update)backend-env.yml; the role default and the SLM group override then work as designed]ai_stack_port8080 vs 11434 (distributed_setupdefault,fix-slm-env-ports.yml)autobot-backend-single-worker.service.j2: forced 1 worker, noExecStartPrebackend_workers=1instead]VITE_API_TIMEOUT60000 (ssot-config.ts) vs 30000 (AppConfig.js, frontend .env.example)config/routes.ts: no importers, about half its routes stalenavItems.tsis the guarded registry]autobot_authvsslm_access_tokenvs theautobot_access_tokenfallbackApiClientdelegates toreadStoredAuthToken; the SLM keeps one key and drops the fallback]cache_managerimports inapi/system.pyget_stats, so cold-start output is unchanged]WorkflowMemory: syncworkflow:memory:(used) vs asyncautobot:workflow:{id}:memory(test-only)/fleet/servicesvs/orchestration/fleet/services, andblue_greenvsdeploymentsrouters, all mountedssot_configvs rawos.getenvin the SLMautobot_sharedreader, after #18094]device_token_service: a weaker, unimported copy ofdevice_jwtutils/hardware_metrics.py(1478 lines) duplicatesperformance_monitoringHardwarePerformanceMonitor, repoint the operator script and tests, then retire the file]is_feature_enabled×4autobot_shared/feature_flags.pycanonical; the rest follow #18094'sconfig/__init__.pywork]Note: the body's "no importer" premise is stale for row 15.
hardware_metricsis now imported by an operator script and by tests.mrveiss commentedon Oct 10, 2026
Owner decision (2026-10-10): every row gets one authority and the copies are retired.
backend_workers: delete thebackend-env.ymloverride.ai_stack_portis 8080.VITE_API_TIMEOUTis 60000, fromssot-config.ts.routes.ts, after a dynamic-loader check.autobot_access_tokenfallback.WorkflowMemory; retire the test-only one./orchestration/fleet/services; the old route returns 410 after the frontend moves, and blue_green folds into deployments.device_token_service.HardwarePerformanceMonitor, then retirehardware_metrics.py.autobot_shared/feature_flagsis canonical.mrveiss commentedon Oct 11, 2026
Status (2026-10-11), branch
issue-17856-concept-forks: rows 2, 3, 5, 9, 10, 11 (fleet half) and 14 are committed. Rows 2, 3 and 5 are being extended to every remaining home of the concept: five other playbook and task literals ofbackend_workers, the inline unit copy infix-backend-deadlock.sh, and one Ansible variable for the AI-stack port./blue-greenis a distinct feature (role borrowing, switch, stop-monitoring, purge, eligible nodes), and/deploymentsis plain role deployment. The fleet-services half is folded. Retiring the old/fleet/servicespath with a 410 waits on the SLM frontend moving offuseOrchestrationManagement.ts.hardware_metrics): blocked onissue-17906-monitoring-launchers, whosestart_monitoring.pystill imports it. Once that lands,HardwarePerformanceMonitormoves intoutils/performance_monitoringand the file retires.mrveiss commentedon Oct 11, 2026
Frontend rows routed (2026-10-11) into the Refined UI build steps (#18237). Each PR carries "Refs #17856 row N".
config/routes.tsonce the dynamic-loader check confirms nothing loads it. Lands with step 2 (shell and nav, Refined UI step 2 · shell: top nav, UI mode, profile appearance #18240).VITE_API_TIMEOUTis 60000, the SSOT value, with a guard. Lands with step 3's ApiClient slice (Refined UI step 3 · shared primitives and one ApiClient #18241).ApiClientdelegates toreadStoredAuthToken; the SLM keeps one key and drops the fallback. Lands with step 3's ApiClient slice (Refined UI step 3 · shared primitives and one ApiClient #18241).Backend and ansible rows are in #18271.
chore(types): regenerate the SLM OpenAPI schema and types for the fle…
mrveiss commentedon Oct 11, 2026
Frontend rows, update (2026-10-11): #18262 (Refined UI step 1) has merged. Row 7 (retire
config/routes.ts) is in progress in step 2, #18240, on branchissue-18240-shell. Rows 6 and 8 (VITE_API_TIMEOUTSSOT;ApiClient→readStoredAuthToken) land with step 3's ApiClient slice (#18241).chore(routes): retire the unused config/routes.ts (#18240)
refactor(dedup): one retention audit emitter, JWT claims decoder, nod…
refactor(cache): api/system.py uses the advanced cache manager; the d…
refactor(orchestration): retire the test-only autobot_shared Workflow…
refactor(auth): retire the unimported services/device_token_service.p…
refactor(slm): /fleet/services delegates to the orchestration handler…
refactor(ansible): backend-env.yml no longer shadows backend_workers;…
refactor(ansible): ai_stack_port is 8080 in distributed_setup and fix…
refactor(ansible): retire the single-worker unit template; the deadlo…
refactor(ansible): backend_workers has one literal; the unit-renderin…
refactor(ansible): retire fix-backend-deadlock.sh, its inline unit co…
refactor(ansible): the AI-stack port is one literal in group_vars/all…
refactor(ansible): the shell scripts fail loudly when ssot-config.sh …
refactor(sudo): retire the unused diagnose-port wrapper subcommand an…