Repository navigation
SPEC 002 Configuration Layer
Rafael Queiroz edited this page Sep 28, 2026
·
6 revisions
| 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 |
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.
| 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). |
| 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 |
- 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 = 0fails; 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
AuditLogwith 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.
- 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 | 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. |