The ecstore/global-state migrations are done (backlog#815, #939, #1052 all closed). Review of every migration-era test/gate measure found three things actually retirable or broken — everything else is a live anti-regression guard and stays. Remove: - scripts/check_metrics_migration_refs.sh — guards a migration that finished: rustfs_metrics:: has zero hits, the metrics crate no longer exists, and the script was never wired into CI or make (only reference was one line in config-model-boundary-adr.md, also removed). - crates/obs init_metrics_collectors — the "backward-compatible alias kept during migration" the removed script was guarding. Zero callers; pure delegate to init_metrics_runtime. Archive (docs/superpowers/plans/, continuing the 2026-07 convention, with the standard archived banner): - startup-timeline.md, scheduler-baseline.md, profiling-numa-capability-inventory.md, kms-development-defaults-inventory.md — one-shot snapshots whose only consumer is the already-archived migration-progress ledger (their same-dir links there start resolving again after the move); zero script pins; fed the closed backlog#660/#665 architecture-review ledger. Fixed the one outbound link (startup-timeline -> readiness-matrix) that the move would have broken — check_doc_paths.sh deliberately does not scan plans/, so nothing else would have caught it. Wire (found orphaned by the same review): - scripts/check_extension_schema_boundaries.sh guards a live contract crate but was never invoked anywhere. Add lint-fmt.mak target, include in pre-commit/pre-pr/dev-check, add ci.yml Quick Checks step (job already installs ripgrep), sync the CONTRIBUTING.md enumerated list, and harden the script against a silently-passing rg probe when src/ is missing. Keep (verified live, documented so the next cleanup pass does not repeat this analysis): - scripts/check_architecture_migration_rules.sh — added a header stating it is a permanent boundary guard, not retirable migration scaffolding; 'migration' in the name is historical. - check_migration_gate_count.sh + floor, delete-marker e2e proof, all pinned docs, compat-cleanup-register sync, remaining inventories (referenced by live docs). Verification: all 7 guard scripts pass, actionlint clean, cargo check --workspace (excl e2e) clean, cargo fmt --check clean. Adversarially reviewed by two independent skeptic passes; their 7 findings (alias left behind, broken outbound link, missing banners, wrong backlog attribution, CONTRIBUTING drift, rg exit-2 hole, missing header rationale) are all folded in.
6.3 KiB
Config Model Boundary ADR
Related issue: rustfs/backlog#660
Task: CFG-002
Decision
Use the existing crates/config package (rustfs-config) as the target owner
for the pure server-config model. Do not create a new config-model crate for
the first extraction.
The next model extraction PR should introduce the model under:
crates/config/src/server_config.rs
The exported path should be:
rustfs_config::server_config::{Config, KV, KVS}
The extraction kept the existing path available through a temporary compatibility re-export:
rustfs_ecstore::config::{Config, KV, KVS}
That re-export included RUSTFS_COMPAT_TODO(CFG-004) and a matching entry in
compat-cleanup-register.md until the model
consumers were migrated. The CFG-004 cleanup removed this old model path after
code scans showed consumers import the model directly from rustfs-config.
Follow-up CFG-008 moved the process-global server-config snapshot accessors
to rustfs_config::server_config after the model path stabilized. Its temporary
rustfs_ecstore::config::{get_global_server_config, set_global_server_config}
compatibility re-export was removed after in-repo runtime consumers migrated to
the rustfs-config owner.
Why rustfs-config
rustfs-config is already the lowest RustFS crate for configuration constants
and subsystem identifiers used by ECStore, notify, audit, targets, scanner, IAM,
and admin code. The current ecstore::config::{Config, KV, KVS} model already
uses rustfs-config constants, so moving the pure model upward to
rustfs-config cuts the wrong dependency direction without adding another crate.
Creating a new crate now would add a second config namespace before consumers are migrated. That would increase re-export and compatibility surface while not removing any storage or runtime dependency by itself.
Allowed Dependencies
The server-config model module may use only:
std::collections::HashMapstd::sync::{LazyLock, OnceLock, RwLock}for the defaultKVSregistration surface and process-global server-config snapshotserdeforKVandKVSserialization compatibilityserde_jsonforConfig::marshalandConfig::unmarshal- existing
rustfs-configconstants and subsystem modules
If serde and serde_json are added to rustfs-config, they should be attached
only to a model feature such as server-config-model unless the implementation
PR proves that making them non-optional is simpler and harmless for downstream
builds.
Forbidden Dependencies
The model module must not depend on:
rustfs-ecstorerustfsStorageAPIor object persistence helpers- notify, audit, targets, IAM, scanner, KMS, or admin handler crates
- async runtimes, HTTP/router crates, object-store crates, or runtime lifecycle state
- unrelated runtime global state outside the process-global server-config snapshot
ConfigSys,read_config_without_migrate,save_server_config, or anycom.rspersistence helper
Boundary Split
Move in the first extraction:
KVKVSConfigDEFAULT_KVSregister_default_kvsConfig::newConfig::get_valueConfig::set_defaultsConfig::marshalConfig::unmarshalConfig::merge
Keep in ecstore:
ConfigSysinit_global_config_systry_migrate_server_configread_config_without_migratesave_server_config- generic
com.rsconfig-object helpers - storage-class runtime global state
Keep default registration wiring in ecstore::config::init until a later PR
extracts a dedicated default-registration contract. The values may be registered
through the moved rustfs_config::server_config::register_default_kvs, but the
startup order and caller remain unchanged.
Move in CFG-008:
GLOBAL_SERVER_CONFIGget_global_server_configset_global_server_config
The temporary ECStore compatibility re-export for these accessors was removed
after code scans showed in-repo consumers use rustfs_config::server_config
directly.
Required Shape Preservation
The extraction PR must preserve:
KV { key, value, hidden_if_empty }#[serde(default, alias = "hiddenIfEmpty")]onKV::hidden_if_emptyKVS(pub Vec<KV>)Config(pub HashMap<String, HashMap<String, KVS>>)KVS::new,get,lookup,is_empty,keys,insert, andextendConfig::new,get_value,set_defaults,marshal,unmarshal, andmergeConfig::new()default application afterecstore::config::init()- existing persisted server-config JSON shape
- existing target, notify, audit, scanner, OIDC, and admin interpretation of
ConfigandKVS
Next PR Requirements
CFG-003 should be a pure model extraction or narrow api-extraction PR. It
must not migrate consumers, change persistence helpers, or alter runtime
behavior.
CFG-004 kept the old rustfs_ecstore::config::* path as a temporary
compatibility shim, registered its removal condition, and removed the shim after
all in-repo consumers migrated.
CFG-005 should migrate external consumers one group at a time after the model
and compatibility path are stable.
CFG-008 moves only the global server-config snapshot accessors to
rustfs-config and migrates in-repo direct consumers. It must not move
ConfigSys, storage-class global state, persistence helpers, default
registration wiring, startup order, or storage behavior.
Verification Gate
Before pushing an extraction PR, run:
- serde roundtrip tests for old and new paths
- tests for
hiddenIfEmptyalias compatibility - tests for
KVSinsertion, lookup, extension, and keys behavior - tests for
Config::new,set_defaults,marshal,unmarshal, andmerge - a cleanup scan proving in-repo consumers no longer use the old
rustfs_ecstore::config::{Config, KV, KVS}model path before removing the compatibility shim cargo tree -p rustfs-config --edges normalcargo tree -p rustfs-ecstore --edges normal./scripts/check_layer_dependencies.sh./scripts/check_architecture_migration_rules.shcargo fmt --all --checkmake pre-commit
Non-Goals
- No consumer migration in
CFG-002. - No code movement in
CFG-002. - No new crate in
CFG-002. - No
com.rsorStorageAPImovement in the first model extraction. - No global server-config state migration until the model path is stable.