Skip to content

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

Open

Description

@mrveiss

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 file secrets.key, ciphertext stored as base64(fernet-token) in secrets.json. It reads only the key file and never consults AUTOBOT_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, then config.secrets_key (AUTOBOT_SECRETS_KEY), then config-manager security.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

  1. mrveiss commented on Oct 10, 2026

    @mrveiss
    OwnerAuthor

    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:

    • row 12 _emit_deletion_audit ×3;
    • row 19, the unverified JWT payload decoders;
    • row 11b _create_node_event (SLM nodes/updates);
    • row 13b, the RS256 denylist key prefix;
    • the row-1 docstring correction (AC2).

    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:

    Row Choice Recommendation
    1 Secrets key source: file-only (SecretsManager) vs env-first (SecretsService) [One shared key resolver under #10088, env key authoritative. Whether AUTOBOT_SECRETS_KEY is set in any deployment is not determined]
    2 backend_workers 4 (role default) vs 1 (playbooks/vars/backend-env.yml, whose include_vars overrides it on every update) [Drop the line from backend-env.yml; the role default and the SLM group override then work as designed]
    3 ai_stack_port 8080 vs 11434 (distributed_setup default, fix-slm-env-ports.yml) [8080; 11434 is the Ollama port]
    5 autobot-backend-single-worker.service.j2: forced 1 worker, no ExecStartPre [Render the canonical unit with backend_workers=1 instead]
    6 VITE_API_TIMEOUT 60000 (ssot-config.ts) vs 30000 (AppConfig.js, frontend .env.example) [60000, the SSOT value]
    7 config/routes.ts: no importers, about half its routes stale [Retire it once no dynamic loader is confirmed; navItems.ts is the guarded registry]
    8 Auth token readers: autobot_auth vs slm_access_token vs the autobot_access_token fallback [ApiClient delegates to readStoredAuthToken; the SLM keeps one key and drops the fallback]
    9 Deprecated cache_manager imports in api/system.py [Use the advanced manager; ensure the client is ready before get_stats, so cold-start output is unchanged]
    10 WorkflowMemory: sync workflow:memory: (used) vs async autobot:workflow:{id}:memory (test-only) [Keep the orchestration one; decide wire-in or retire for the shared one]
    11 /fleet/services vs /orchestration/fleet/services, and blue_green vs deployments routers, all mounted [Pick one public path. Which path the frontend actually calls is not determined: code and comment disagree]
    13 Internal API key: ssot_config vs raw os.getenv in the SLM [One autobot_shared reader, after #18094]
    14 device_token_service: a weaker, unimported copy of device_jwt [Retire it after a dynamic-loader check]
    15 utils/hardware_metrics.py (1478 lines) duplicates performance_monitoring [Move HardwarePerformanceMonitor, repoint the operator script and tests, then retire the file]
    16 is_feature_enabled ×4 [autobot_shared/feature_flags.py canonical; the rest follow #18094's config/__init__.py work]

    Note: the body's "no importer" premise is stale for row 15. hardware_metrics is now imported by an operator script and by tests.

  2. added
    needs-decisionBlocked on an owner decision; options and a recommendation are on the issue
    on Oct 10, 2026
  3. mrveiss commented on Oct 10, 2026

    @mrveiss
    OwnerAuthor

    Owner decision (2026-10-10): every row gets one authority and the copies are retired.

    • Secrets: one key resolver, env first, toward Umbrella/PRD: unify AutoBot secrets — one RBAC-governed store, vaults + one key abstraction (replaces 11 stores, 5 keys, 2 UIs) #10088.
    • backend_workers: delete the backend-env.yml override.
    • ai_stack_port is 8080.
    • Retire the single-worker unit template; the canonical unit renders with 1 worker.
    • VITE_API_TIMEOUT is 60000, from ssot-config.ts.
    • Retire routes.ts, after a dynamic-loader check.
    • One auth-token reader per app; the SLM drops the autobot_access_token fallback.
    • Move to the advanced cache manager with cold-start stats preserved, and delete the deprecated one.
    • Keep the orchestration WorkflowMemory; retire the test-only one.
    • Public fleet path is /orchestration/fleet/services; the old route returns 410 after the frontend moves, and blue_green folds into deployments.
    • One internal-API-key reader.
    • Retire device_token_service.
    • Move HardwarePerformanceMonitor, then retire hardware_metrics.py.
    • autobot_shared/feature_flags is canonical.
  4. removed
    needs-decisionBlocked on an owner decision; options and a recommendation are on the issue
    on Oct 10, 2026
  5. mrveiss commented on Oct 11, 2026

    @mrveiss
    OwnerAuthor

    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 of backend_workers, the inline unit copy in fix-backend-deadlock.sh, and one Ansible variable for the AI-stack port.

  6. mrveiss commented on Oct 11, 2026

    @mrveiss
    OwnerAuthor

    Frontend rows routed (2026-10-11) into the Refined UI build steps (#18237). Each PR carries "Refs #17856 row N".

    Backend and ansible rows are in #18271.

  7. mrveiss commented on Oct 11, 2026

    @mrveiss
    OwnerAuthor

    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 branch issue-18240-shell. Rows 6 and 8 (VITE_API_TIMEOUT SSOT; ApiClient → readStoredAuthToken) land with step 3's ApiClient slice (#18241).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions