.ai/principles/distilled/cicd-internals.md
lib/gitlab/ci/config/entry/; for EE-specific changes, use ee/lib/gitlab/ci/config/entry/ or ee/lib/ee/gitlab/ci/config/entry/.schema.md) whenever a new keyword is added or modified.Entry::Node for simple keywords, Entry::Simplifiable for keywords with multiple structures, Entry::ComposableArray for lists of single-type sub-elements, and Entry::ComposableHash for single-type sub-elements with user-defined keys.Entry::Validatable to enable the validations block, Entry::Attributable to expose xxx/has_xxx?/has_xxx_value? helpers, and Entry::Configurable to expose xxx_defined?/xxx_entry/xxx_value helpers.xxx_value method (not direct attribute access) to retrieve the value of a nested entry inside the value method.value method only when the default Entry::Node behaviour (returning the hash configuration) is insufficient; use xxx_value for nested entries and plain attribute accessors for simple attributes.Entry::Node#value (or a private helper) using Gitlab::Ci::Config::FeatureFlags.enabled?(:flag, type: :beta) rather than scattering flag checks across callers.Feature.enabled?(:flag, Feature.current_request) or Config::FeatureFlags.enabled?(:flag), or move the flag check outside the entry class entirely.spec/lib/gitlab/ci/yaml_processor_spec.rb or the files under spec/lib/gitlab/ci/yaml_processor/test_cases/ for every new or changed keyword.belongs_to association to a partitionable table from the start, to reduce future migration work.p_ (e.g., p_ci_examples); DO NOT use the p_ prefix for partition names.partition_id column in every new CI routing table; its value must equal the partition_id of the related association (e.g., p_ci_builds).[:id, :partition_id] to allow efficient lookup by id alone.ON UPDATE CASCADE using add_concurrent_partitioned_foreign_key so that partition_id can be updated during partition re-balancing.with_lock_retries and explicit LOCK TABLE statements) rather than relying on the application boot-time initializer, to prevent node startup failures under high traffic.gitlab_partitions_dynamic schema; use 100 as the starting value for partition_id.Ci::Partitionable in the model, set self.table_name to the routing table, set self.primary_key = :id, and declare partitionable scope: :<association>, partitioned: true.PARTITIONABLE_MODELS list in app/models/concerns/ci/partitionable.rb and register it in the config/initializers/postgres_partitioning.rb initializer.For the full picture, see: