Summary
The configuration surface has drifted in both directions. 18 keys exist in the Zod schema but not in .env.example. 10 keys exist in .env.example but bypass Zod validation entirely via hand-rolled parseInt. Several more are read directly off process.env in feature code.
Direction 1 — undocumented keys (18)
AUTH_JWT_SECRET DB_POOL_MIN
AUTH_ACCESS_TOKEN_TTL_SECONDS DB_POOL_MAX
AUTH_REFRESH_TOKEN_TTL_SECONDS DB_POOL_ACQUIRE_TIMEOUT_MS
AUTH_SESSION_MAX_TTL_SECONDS DB_POOL_HEALTH_CHECK
DB_BACKUP_DIR DB_MAINTENANCE_INTERVAL_MS
DB_MAINTENANCE_VACUUM_THRESHOLD DB_BACKUP_RETENTION_COUNT
ERROR_REGISTRY_MAINTENANCE_INTERVAL_MS REGISTER_RATE_LIMIT_MAX_REQUESTS
ERROR_REGISTRY_CAP_PER_AGENT HEALTH_PROBE_TIMEOUT_MS
AUTH_JWT_SECRET is the critical one and is tracked as a security issue. The rest include the entire connection-pool configuration, which suggests the pool abstraction was added without its configuration being documented.
Direction 2 — unvalidated keys (10)
These are in .env.example but not in the config schema. The 6 rate-limit keys are parsed by a hand-rolled parseInt with a > 0 fallback (rateLimit.ts:237-244); the 4 Venice cache keys are read straight off process.env (venice/client.ts:75-98).
A typo silently falls back to the default. RATE_LIMIT_PUBLIC_MAX_REQUEST=999999 (missing the S) does not error — it quietly yields 120.
services/featureFlags.ts:44 repeats the pattern for FEATURE_<FLAG> with its own parseInt.
Direction 3 — direct reads in feature code (10+)
SKIP_STELLAR_ACCOUNT_VERIFY (agents.ts:268)
NODE_ENV (agents.ts:278)
ADMIN_AUDIT_DB_PATH (adminControl.ts)
ADMIN_BACKUP_DIR (adminControl.ts)
AI_NET_READ_ONLY (middleware/readOnly.ts)
AI_NET_READ_ONLY_REASON (middleware/readOnly.ts)
QUALITY_* (qualityScorer.ts, 6 keys)
IDEMPOTENCY_TTL_MS (services/idempotency.ts)
IDEMPOTENCY_CLEANUP_MS (services/idempotency.ts)
Direction 4 — stale PostgreSQL references
db/pool.ts (424 lines) and .env.example:16 describe the connection as SQLite/PostgreSQL, and db/events.sql:9 explicitly notes the DDL "is not compatible with PostgreSQL". Meanwhile the pool abstraction and four DB_POOL_* keys (min, max, acquire timeout, health check) imply a connection pool — which a single-writer synchronous engine like SQLite does not need. This is unresolved architectural drift, not a docs problem.
Acceptance criteria
Summary
The configuration surface has drifted in both directions. 18 keys exist in the Zod schema but not in
.env.example. 10 keys exist in.env.examplebut bypass Zod validation entirely via hand-rolledparseInt. Several more are read directly offprocess.envin feature code.Direction 1 — undocumented keys (18)
AUTH_JWT_SECRETis the critical one and is tracked as a security issue. The rest include the entire connection-pool configuration, which suggests the pool abstraction was added without its configuration being documented.Direction 2 — unvalidated keys (10)
These are in
.env.examplebut not in the config schema. The 6 rate-limit keys are parsed by a hand-rolledparseIntwith a> 0fallback (rateLimit.ts:237-244); the 4 Venice cache keys are read straight offprocess.env(venice/client.ts:75-98).A typo silently falls back to the default.
RATE_LIMIT_PUBLIC_MAX_REQUEST=999999(missing theS) does not error — it quietly yields 120.services/featureFlags.ts:44repeats the pattern forFEATURE_<FLAG>with its ownparseInt.Direction 3 — direct reads in feature code (10+)
Direction 4 — stale PostgreSQL references
db/pool.ts(424 lines) and.env.example:16describe the connection as SQLite/PostgreSQL, anddb/events.sql:9explicitly notes the DDL "is not compatible with PostgreSQL". Meanwhile the pool abstraction and fourDB_POOL_*keys (min, max, acquire timeout, health check) imply a connection pool — which a single-writer synchronous engine like SQLite does not need. This is unresolved architectural drift, not a docs problem.Acceptance criteria
.env.exampleand the Zod schema agree in both directions, enforced by a CI test.parseIntfallback that silently defaults is replaced with a validation error, or documented as an intentional default.process.envreads in feature code are moved into the config module, leavingprocess.envaccess confined to config, logger, and CLI entry points.process.envreaders outside the config module.DB_POOL_*keys are documented and their effect on the SQLite path is stated explicitly.