Skip to content

SPEC 002 Configuration Layer

Rafael Queiroz edited this page Sep 28, 2026 · 6 revisions

SPEC-002 — Configuration Layer

Status Draft
PRD source §8.7 (FR-8.41–8.50)
Depends on —
Required by All specs; blocking for SPEC-008, SPEC-021
Milestone M0

Description

A runtime configuration layer so that operational parameters are settings rather than constants requiring a release to change.

Nearly every number in the PRD is a starting guess made before the system has run — quote cadence, staleness thresholds, budget reserve. Some will be wrong, and finding out is the point. A guess that takes a deploy to correct stays wrong for a sprint.

This spec is blocking for SPEC-008, not merely useful to it: FR-6.15 requires the market data service to change its own polling cadence at runtime under budget pressure, which is unimplementable if the interval is a constant in the polling job.

Business rules

ID Rule
BR-002-01 Operational parameters are read from configuration at runtime. Introducing a new tunable means adding a registry key, never a literal in application code.
BR-002-02 Resolution order is built-in default → deployment/environment → per-tenant override → per-user preference; most specific wins.
BR-002-03 Each key declares which levels may set it. A key not marked user-settable must be rejected if a user attempts to set it — this is a tenant-isolation concern, not just validation.
BR-002-04 Every key declares a type and permitted range, validated at startup. An invalid value fails the boot loudly. Silent fallback to a default is prohibited: a cadence of 0 must never be interpreted as "poll continuously".
BR-002-05 Values the system adjusts autonomously (SPEC-008 cadence degradation) are stored as runtime state, in a store distinct from operator-set configuration.
BR-002-06 An autonomous adjustment must never be silently reverted by a deploy, and must never be presented to an operator as an intentional setting.
BR-002-07 Configuration changes affecting behaviour are written to AuditLog with actor, previous value and new value.
BR-002-08 Secrets are not configuration in this sense. They live in the managed secret store and are excluded from any config listing, export, log or error message.
BR-002-09 The effective configuration — each resolved value and which level supplied it — is inspectable by an operator without reading source.
BR-002-10 Per-user preferences are tenant-scoped data and subject to isolation (SPEC-003) and export/deletion (SPEC-004).

Initial registry

Key Default Levels PRD source
quotes.cadence_minutes 30 Deployment FR-6.1, FR-6.15
quotes.degradation_ladder 30 → 60 → 120 Deployment FR-6.15
quotes.ondemand_reserve_pct 10 Deployment FR-6.21
quotes.monthly_quota 15000 Deployment F6.1
quotes.budget_alert_pct 70 Deployment FR-6.13
quotes.provider brapi_free Deployment FR-6.10
quotes.ondemand_rate_limit — Deployment FR-6.22
quotes.close_capture_time 22:00 Deployment FR-6.2, SPEC-008 BR-008-09 (#171)
quotes.cotahist_annual_min_days 100 Deployment SPEC-008 BR-008-30 (#171)
quotes.cotahist_timeout_ms 300000 Deployment SPEC-008 BR-008-30 (#171)
market.trading_calendar B3 calendar (data) Deployment FR-6.6
import.staleness_days 30 Deployment / user FR-4.2
import.reminder_enabled off (opt-in) User FR-4.3
import.max_upload_mb 10 Deployment FR-2.4
import.subscription_credit_window_days 120 Deployment SPEC-005 BR-005-20d (#144)
import.subscription_close_lookback_days 10 Deployment SPEC-005 BR-005-20d (#144)
reports.concentration_threshold_pct 20 User FR-5.24
reports.default_grouping asset class / asset User FR-5.28
reports.benchmarks CDI, IPCA, IBOV User FR-5.4
auth.session_idle_days 30 Deployment FR-1.4
retention.audit_months 12 Deployment FR-8.17
retention.deletion_window_days 30 Deployment FR-8.12
features.ingestion_adapters off Deployment (flag) FR-4.5
wallets.drift_tolerance_pp 5 User FR-7.15
notifications.email_enabled off (opt-in) User FR-9.25
notifications.opportunity_cooldown_hours 24 User FR-9.22
notifications.quiet_hours 20:00–08:00 Deployment / user FR-9.27
backup.retain_count 14 Deployment FR-8.66
personal.catchup_max_days 30 Deployment FR-8.72

Acceptance Criteria

  • Every key in the registry above resolves at runtime with its documented default and no code change.
  • Setting a key at deployment level overrides the built-in default; a per-user preference overrides both, for keys marked user-settable.
  • A user attempting to set a deployment-only key is refused.
  • Booting with an out-of-range or wrong-typed value fails the boot with a message naming the key, the offending value and the permitted range.
  • Booting with quotes.cadence_minutes = 0 fails; the system does not start and does not fall back to a default.
  • SPEC-008 can change the effective cadence at runtime, and the change survives a subsequent deploy.
  • An operator can distinguish a system-degraded cadence from an operator-set one.
  • Every behaviour-affecting config change appears in AuditLog with before and after values.
  • No secret value appears in the effective-configuration view, any export, or any log line.
  • An operator can view the resolved configuration with the origin level of each value.
  • Grepping the codebase for the registry's default values finds them only in the registry definition.

Out of Scope

  • A configuration admin UI. Deployment-level config is set through environment/deployment mechanisms; only per-user preferences get interface surfaces, owned by their feature specs.
  • Hot reload of deployment-level config without restart, unless a key explicitly requires it (quotes.* runtime state excepted, per BR-002-05).
  • Secret management itself — the managed secret store is infrastructure, not this layer.
  • Per-tenant billing plans or entitlements.
  • A/B testing or experiment frameworks.
  • Making calculation conventions, security controls or monetary precision configurable — explicitly forbidden (see Decision Logs).

Decision Logs

# Decision Alternatives considered Rationale
DL-002-01 Startup validation fails the boot on an invalid value. Log a warning and fall back to the default A silent fallback hides a misconfiguration until it causes damage — cadence = 0 falling back to 30 looks fine until someone reads the code. Failing loudly at boot is discovered in seconds; a silent fallback is discovered by a burnt quota.
DL-002-02 Autonomous adjustments stored separately from operator config. One store for both If SPEC-008 writes a degraded cadence into the same store an operator uses, nobody can tell an intentional setting from an automatic one, and the next deploy silently reverts a degradation the system needed.
DL-002-03 Calculation conventions are NOT configurable (FR-8.48). Expose average-cost vs FIFO, TWR vs XIRR as settings Two users' reports would become incomparable, and one user's own history unreproducible — flip the setting and last year's return silently changes. These are versioned product decisions with migrations, not settings.
DL-002-04 Security and compliance controls have no "off" key (FR-8.49). Allow disabling for local development A disable path that exists in code will eventually run in production. Where a compliance value is genuinely a parameter (retention period), it is configurable within a validated range that cannot be set to an unlawful value.
DL-002-05 Monetary precision and rounding are fixed (FR-8.50). Configurable decimal places Configurable precision produces figures that disagree between environments — the worst class of bug, invisible until someone reconciles two numbers that should match.
DL-002-06 Four-level resolution rather than two. Default + environment only Several values are genuinely per-user preferences (concentration threshold, default grouping, benchmark selection) and several are genuinely operational. Collapsing the levels would force user preferences into feature-specific storage and lose the single validated registry.

Clone this wiki locally