Supporting reference · Working design and evidence, not a promise of complete support.

On this page

Rails Field lowering

Status: Implemented for ten scalar kinds, enums, Counters, and attachment and image uploads. Money, position, secure token, and JSON Fields are implemented with generator-parity storage and partial GapSet entries. Other Field kinds and modifiers are evidence-backed directions.

Each emitted scalar, enum, or Counter Field becomes one PostgreSQL column plus the model declarations that Rails needs to read, write, validate, and display it. The Compiler emits ten ordinary scalar kinds, qualifying enums, Counters, maintained by Rails counter_cache where it can, and uploads that Active Storage records instead of a Domain column. For money, position, secure token, and JSON Fields it emits what rails generate scaffold or a developer writing by hand would produce, and lists the kind's missing meaning as a foundation_plan.gap.field_kind.partially_generated record. That record says the Field is entered or displayed only where a generated form or page carries it. A Primary Descriptor that selects one of these Fields stays a foundation_plan.gap.primary_descriptor.not_generated record. Other Field kinds are omitted and listed in the reviewed GapSet. Modifiers lower one by one: immutability becomes attr_readonly, log redaction filters the attribute, normalization becomes Rails normalizes, and case-insensitive comparison becomes citext. A modifier the target cannot realize is listed on its own. Encryption and derived numbers remain directions. The Field catalog states what each kind and modifier means, and the support inventory (repository-only) records which kinds generate.

On this page

Realized defaults and modifiers

Defaults are realized for compatible literals on emitted boolean, integer, decimal, money, short-text, and long-text Fields, exact current_date and current_time on required date and datetime Fields, and in-domain literal keys on admitted enums. On emitted ordinary scalar and admitted enum Fields, log redaction adds the attribute to self.filter_attributes and registers only the model-qualified request parameter. The same key under another model remains visible; arbitrary application, provider, and external logs are outside this boundary. Authored normalizations are realized only on emitted scalar Fields. Immutability is realized on emitted scalar Fields and admitted enum Fields; the encompassing gap for an unsupported Field shape covers that Field and its authored modifiers.

Defaults

Support: see the support inventory (repository-only) rows for Field defaults.

A literal default on an emitted boolean, integer, decimal, money, short-text, or long-text Field becomes an ordinary migration column default, such as t.boolean "finished", default: false, null: false. The canonical schema carries the same default, and Active Record reads it from the column, so a new model exposes it before persistence. An explicitly supplied value wins, including false, 0, and nil on an optional Field. The Analyzer's literal typing decides compatibility. The target then adds its storage bounds: an integer must fit PostgreSQL integer, a decimal must fit unconstrained numeric, and money must fit its numeric(12, 2) column. Rails' schema dumper writes a decimal default with a fractional part, so "10" appears as default: "10.0", on money as on decimal. A column default bypasses Rails normalizes, so a text literal that the Field's authored normalizations would change stays a gap rather than storing an unnormalized value. Direct SQL inserts also receive the database default. A null literal and literals on other Field kinds, including JSON, remain foundation_plan.gap.field_modifier.default records; position and secure token Fields take no default.

The exact { "kind": "environment", "name": "current_time" } default on an emitted required datetime Field lowers to a model-visible attribute :published_at, default: -> { Time.current } declaration, and current_date on a required date Field to attribute :starts_on, default: -> { Date.current }. Omitting a type preserves the schema-derived column type, including PostgreSQL timestamp(6) precision. Active Record materializes the callable on a new model before ordinary presence validation; an explicit nil remains invalid and an explicitly supplied value remains unchanged. The Domain migration and canonical schema retain NOT NULL with no database default, so direct and bulk inserts must supply the value. The callable follows Active Record's new-record attribute lifecycle rather than database-commit time. Optional environment defaults remain gaps. The separate enum rule below owns its literal-key defaults.

Required enum Fields

Support: see the support inventory row (repository-only).

The current Compiler admits a required enum with its canonical nonempty ordered domain. The reviewed Plans contribute Oscar Party's ordinal bookmark.priority and non-ordinal credit.role; Case Chat's case.status, participant.role, participant.notification_level, and notification.kind; and Photogram's feed_occurrence.reason. Each emits one PostgreSQL string column with null: false and an explicit stable-key Rails enum mapping with validate: true and collision-aware native helper names, plus ordinary presence validation for the required Field and generated schema-quality check. The target admits that enum only when Rails' pluralized class mapping method is safe in both the frozen profile and selected dependencies, unique among sibling enums, and distinct from authored Predicate and Ordering scope names. A collision omits the Field and records the exact foundation_plan.gap.field_kind.not_generated reason. It emits no native PostgreSQL enum or database CHECK. Direct SQL and validation-bypassing writes such as update_all therefore remain outside membership proof. Any admitted required enum accepts a valid in-domain literal-key default. Oscar's bookmark.priority emits default: "normal"; Case Chat's case.status and participant.notification_level emit default: "open" and default: "all_activity" in the model declaration, migration, and schema. Active Record materializes the model default, while an explicit compatible key wins. A nonliteral default or a literal outside the closed domain remains a precise foundation_plan.gap.field_modifier.default record. An enum Field the Domain does not emit keeps its encompassing Field gap. Enums rejected by the mapping-name rule above use that same encompassing Field gap. Outside the descending ordinal pattern in Named Orderings, other enum Primary Descriptors, Orderings, Field-owned enum Validations, and ordinal rank comparisons likewise remain ungenerated and are disclosed through the reviewed GapSet. Admitted enum Field projections and form labels use the same enums.<model>.<field>.<key> Rails I18n entries seeded from authored names. Form values remain stable keys in authored order; display labels do not imply ordinal rank semantics. Native helper naming follows the model helper allocation rules. Admitted storage feeds the existing generic local ExpressionSql rule, but an ordinal comparison lowers only when it does not depend on authored rank. An independently admitted predicated direct Association may consume a non-ordinal scope under the relationship rule's existing gates; the reviewed Plans add no Association consumer.

An admitted required enum also emits an ordinary string column with null: false. Its model uses an explicit stable-key Rails enum mapping with validate: true and collision-aware native helper names, plus ordinary presence validation. The explicit presence validator lets the generated schema-quality check recognize the required Field; active_record_doctor 2.0.1 misses Rails 8.1's string-keyed enum inclusion validator. Admission requires the plural mapping name to be target-safe, unique among sibling enums, and distinct from authored Predicate and Ordering scope names. It emits no native PostgreSQL enum or database CHECK; raw SQL and validation-bypassing writes remain outside the membership proof. Every admitted required enum accepts an in-domain literal-key default. Oscar's bookmark.priority emits default: "normal"; Case Chat's case.status and participant.notification_level emit default: "open" and default: "all_activity" in the model declaration, migration, and schema. Active Record materializes the model default on a new record, while an explicit compatible key wins. Nonliteral and out-of-domain defaults remain exact modifier gaps. An enum Field the Domain does not emit keeps its encompassing Field gap. This includes a required enum whose plural mapping name conflicts with the target class namespace, a sibling enum, or an authored Predicate or Ordering scope. Outside the descending ordinal Ordering pattern, Field-owned enum Validations, descriptors, other Orderings, and ordinal rank comparisons remain unsupported or omitted. A required non-ordinal enum may participate only as the Field member in Credit's exact admitted Entity-owned uniqueness tuple. Admitted enum Field projections and form option labels share Rails I18n entries seeded from authored value names. Forms submit stable keys in authored order. Editable display labels do not change stored keys or imply ordinal rank semantics. The ordinary attribute may feed the existing generic local Predicate rule and, after independent admission, the existing predicated direct Association rule. The reviewed Plans add two non-ordinal Predicate scopes and no Association consumer. On an admitted enum, the retained plural mapping method and collision-aware native value helpers are target realization details and add no GapSet record.

The model provenance includes the Field and every contributing FieldValue; migration and schema provenance need only the Field because their bytes do not encode membership.

Optional enum Fields

Support: see the support inventory row (repository-only).

An optional enum uses the same mapping, naming, collision, and literal-default rules as a required one. Its string column is nullable, and its declaration uses Rails' own nil-permitting validation from the pinned enum source:

enum :failure_category, {"temporary" => "temporary", "invalid_input" => "invalid_input"},
  validate: {allow_nil: true}

No presence validation is added. Forms keep the blank select option that every enum select already offers, and Active Record's enum type stores a submitted blank as nil. Read-only projections show the shared missing-value text for nil instead of looking up an enum label. Validation conditions and Orderings over an optional enum stay outside the admitted shapes listed above.

Money

Support: see the support inventory row (repository-only).

The owner chose generator-parity storage for this release instead of the documented money-rails direction. A money Field becomes t.decimal precision: 12, scale: 2, a number_field with step: 0.01, and number_to_currency on show and list pages. Its numericality: {greater_than: -10**10, less_than: 10**10} validation keeps amounts within what that column stores, so an oversized amount is a form error instead of a failed save; ordinary numeric validation explains the bound. A USD Field uses the locale's currency format; another fixed currency is shown with its code. BigDecimal storage keeps amounts exact, but the generated app has no Money object. Currency-aware arithmetic, allocation, and rounding remain the Field's partial gap, and a money Field's own comparison Validations remain Validation gaps because decimal literal comparisons are not admitted.

Positions

Support: see the support inventory row (repository-only).

A position Field becomes a required integer with integer numericality validation and a number input when a Scaffold lists it. Import records its settings.within terms. When a new record arrives without a position, the model appends it to the end of its partition:

before_validation on: :create, if: -> { position_before_type_cast.nil? } do
  self.position = (self.class.where(post_id:).maximum(:position) || 0) + 1
end

The callback lets a create form omit the position, as most Plans do. A save with validate: false skips it, so that caller supplies the position. An admitted Ordering may sort by the column. Contiguous renumbering after deletes, moves between partitions, concurrent appends, and drag reordering remain the Field's partial gap; the positioning gem stays the direction for that work.

Secure tokens

Support: see the support inventory row (repository-only).

A secure token Field becomes a string column with a unique index and Rails has_secure_token, which fills the token when the record is initialized. It is never a form input or strong parameter. Show and list pages display it where the Plan projects it. A required token still gets presence validation, and an immutable token joins attr_readonly. Factories and development records leave it to Rails. Lookup by token, regeneration, expiry, and digest storage remain the Field's partial gap. Account registration coverage for a token on the Account Entity is owned by the Account lowering.

Immutable Fields

An emitted scalar or admitted enum Field with immutable: true is included in the model's attr_readonly declaration. Creation may assign the value or use any realized default. After persistence, ordinary changed, same-value, and nil assignments raise ActiveRecord::ReadonlyAttributeError under the pinned Rails 8.1 defaults. This is model-level write-once behavior, not a database trigger or a fence against direct SQL. Current generated-app proof covers case.reference_number, case.opened_at, and post.published_at, plus immutable notification.kind and feed_occurrence.reason; a modifier on an ungenerated Field kind remains a target-support gap.

An emitted scalar or admitted enum Field with immutable: true joins that model's attr_readonly declaration. Its subject UUID joins the generated model's provenance. Creation still accepts an explicit value or a realized default. After persistence, ordinary changed, same-value, and nil assignments raise ActiveRecord::ReadonlyAttributeError. Like immutable Reference enforcement, this is a model-level write-once boundary rather than a database trigger or a fence against direct SQL. An immutable modifier on a Field shape the Domain does not emit remains in the reviewed GapSet.

Sensitive Fields

Use Active Record Encryption as the first direction for encrypted_at_rest. On emitted ordinary scalar and admitted required enum Fields, redact_from_logs appends the attribute to self.filter_attributes and registers the model-qualified request parameter. Case Chat filters notification.deduplication_key; the same key under another model remains visible. This boundary does not encrypt the value or cover arbitrary application, provider, or external logs. The modifier remains a reviewed gap on every other or unemitted Field. A Predicate, uniqueness rule, or future lookup that reads an encrypted Field still requires a supported query realization rather than silently enabling deterministic encryption.

Text normalization

Lower an explicit Field pipeline with Rails normalizes, grouping Fields with identical pipelines under one readable inline lambda. The Field catalog owns character semantics and the cleanup-before-blank admission rule. Use the public StripAttributes.strip(value) formatter for adjacent trim, blank_to_null; trim alone passes allow_empty: true. The generated dependency contributor pins strip_attributes to 2.0.1 only when a retained normalization pipeline includes trim. Do not install its model callback. Native Rails value.squish realizes collapse_whitespace, and Rails value.presence realizes blank_to_null. Append presence only when authored. Ruby String#downcase supplies the full Unicode lowercase mapping. Preserve operation order and nil, including after an intermediate blank-to-null result. No type-wide default or application formatter wrapper is added. Loading StripAttributes adds its strip_attributes method to every model. Reserve that name only when retained trim actually selects the dependency. If colliding Fields are the only trim selectors, retain their storage and decline each complete normalization pipeline with the existing modifier gap. Otherwise, independently retained trim makes the collision real: omit the affected member and dependent consumers through ordinary gaps. Native enum prefixes and AASM namespaces resolve generated convenience-method collisions where available, and a Predicate or Ordering named strip_attributes keeps its scope under the key plus the table name, as Scopes describes. The collision qualification (repository-only) records the library behavior, selection-cycle rationale, and runtime boundary. An authored Entity whose model constant is StripAttributes makes the formatter unavailable application-wide. Preserve that Entity and its storage, omit every complete trim-containing pipeline with a normalization modifier gap, and select no formatter gem. Rails-only pipelines remain eligible. This handles the actual optional-module collision without reserving the Entity name in applications that do not need the formatter. Trim removes Unicode whitespace and six additional invisible edge characters while preserving NUL. Collapse preserves those invisibles but removes edge NUL; both retain interior joiners. These policies intentionally differ. Ordinary scalar hash equality receives normalization and handles an operand that normalizes to nil. Typed Arel casts non-null normalized values, but its null operator and hash-array membership are selected before normalization. Generated Arel, array, untyped, and raw-SQL consumers must call Model.normalize_value_for first and branch on nil.

Text comparison

The current Compiler lowers an emitted short_text Field with case_insensitive comparison to PostgreSQL citext. One conditional migration installs the extension before every Domain table, and db/schema.rb declares both the extension and t.citext. Entered case remains stored unless an authored normalization changes it, while ordinary Active Record hashes, typed Arel equality, ordering, and B-tree indexes compare case-insensitively. The generated-app qualification verifies that the extension's schema is on the current search_path. Its pattern operators and several string functions are also case-insensitive; cast to text for a deliberate exact operation. Pin or verify a supported database LC_CTYPE, or disclose it as an external prerequisite, because that creation-time setting controls case folding. The bounded uniqueness slice inherits each admitted tuple member's storage equality, including compound mixtures of citext, exact short_text, date, and foreign-key members. Entity and Field comparison Validations with Field operands likewise require compatible comparison semantics rather than relying on PostgreSQL's mixed citext/text resolution. Exclusion must inherit the Field's comparison behavior instead of Ruby String membership accidentally becoming case-sensitive. Field-to-Field Expressions require the same compatible comparison semantics before lowering. Nondeterministic ICU collations remain a future profile strategy if representative multilingual identifiers require more complete Unicode case behavior.

Counters

Support: see the support inventory row (repository-only).

A Counter becomes an integer column with default: 0, null: false, maintained by Rails' built-in counter_cache on the child's belongs_to. Photogram's post.likes_count counts post.likes, whose Reference is like.post, so the Like model declares belongs_to :post, counter_cache: true. When the Counter's key is not Rails' default <children>_count name, the option names the column, as in belongs_to :followed, class_name: "User", counter_cache: :followers_count. Rails documents the has_many :counter_cache option for exactly that custom-name case, so the emitted has_many for the counted Association names the same column. Its size then reads the cache, and Rails knows that the child's belongs_to already maintains the count.

The counted Association must be a direct, unpredicated, referenced-side Association over an ordinary single-target Reference, and only one Counter may count through each Reference. A polymorphic Reference works too when every target counts it in a column of the same name: Rails updates that column on whichever target a record references. A Like whose target is a Post or a Comment declares belongs_to :target, polymorphic: true, counter_cache: true when both count their likes in likes_count. An exclusive arc declares one belongs_to per target, so each target's belongs_to carries the counter_cache: of the Counter that counts it, as Dunbar150's post.likes_count and comment.likes_count do. Generated-model checks create and destroy Likes on both targets for both realizations.

Every other Counter keeps its column, its projections, Orderings, and Predicates, and reads 0 until application code maintains it. A Policy that reads it, directly or through a Predicate, would decide access from that 0, so it becomes a Policy stub until the counting is written. Its maintenance is left out behind a model example that creates one counted record and expects the column to read 1; the README lists it under Behavior to write, and the GapSet lists it as partially generated with its reason. The reason for an indirect count names the direct Association it goes through, because counting those join records gives the same number when each joined pair is unique; its example creates one join record with both of its References set. A count whose example needs a Reference the Compiler does not emit, or setup that breaks a conditional Validation, is listed under Test coverage to complete instead. A filtered count needs a scoped maintenance path that counter_cache does not offer, so its example, which cannot know which records the Predicate selects, is listed under Test coverage to complete instead. An earlier release omitted the column and everything that read it.

Rails owns the value. A Counter is never a form input, permitted parameter, factory attribute, or development seed value. An authored Counter input is dropped and listed in the GapSet while the rest of the form is kept. Explicit index, show, and collection-row projections display each emitted Counter they do not already select, after the authored items. An omitted projection keeps its descriptor-only presentation. A counter-backed Ordering follows the ordinary Ordering lowering; Photogram's post.most_liked becomes a scope and its composite index.

Rails 8.1 increments on create, moves the count when the foreign key changes, and decrements when it destroys the child row. It skips the decrement on the parent that is itself being destroyed. A cascading deletion into a child that carries a counter_cache therefore uses dependent: :destroy, so destroying a User decrements the like counts on other Users' posts. Foreign keys stay NO ACTION, so no database cascade can bypass that path. The pinned active_record_doctor does not see the decrement as a destroy callback, so the generated configuration lists those Associations under incorrect_dependent_option rather than taking its delete_all suggestion.

Bulk writes such as delete_all, update_all, insert_all, and raw SQL skip the callbacks and leave counts stale; Rails' reset_counters repairs one record. Generated repair tasks and drift detection remain deferred, with Counter Culture still the audited candidate for that work.

JSON values

Support: see the support inventory row (repository-only).

The semantic json Field lowers to PostgreSQL jsonb, which PostgreSQL recommends for most applications and Active Record maps to ordinary Ruby values. There is no json versus jsonb Plan choice. Keep stable application facts as Fields, References, or Entities. If exact source bytes matter, store the raw input separately from the parsed JSON value.

A form edits the document as JSON text in a textarea. Active Record's JSON type would store submitted text as a JSON string, so the model writer parses a String and reports malformed text as an ordinary invalid error on the Field. Show pages print the document with JSON.pretty_generate. Document structure and schema validation remain the Field's partial gap.

Rich text

Support: see the support inventory row (repository-only).

Action Text is the direction for rich_text, and it needs owner sign-off because it adds framework-owned records, direct uploads, and attachment authorization. Until then the Field lowers at generator parity with long_text: a text column, a textarea, a presence validation when required, and plain-text display. Formatting, embedded attachments, and sanitized HTML display remain the Field's partial gap.

URLs

Support: see the support inventory row (repository-only).

A url Field is a string column with a url_field input. Rails has no URL validator, and the Rails Guides document a custom EachValidator as the extension point, so a Plan with a url Field gets app/validators/url_validator.rb, as Mastodon has. It parses the value with Ruby's standard URI.parse and adds a :url error unless the result is an http or https URI with a host. URI::InvalidURIError is its parse-failure signal, so it rescues that error. The locale adds errors.messages.url: "is not a valid URL". The validate_url gem that Forem uses was set aside: its last release, 1.0.15, was in May 2022.

The model declares validates :website, url: true and leaves a blank value to requiredness, as format and length declarations leave nil: a blank required Field reports only "can't be blank", and a blank optional Field is valid. A browser submits an empty URL input as an empty string, so the declaration adds allow_blank: true, as Mastodon's status_page_url and Forem's profile website_url do. A Field whose normalization includes blank_to_null stores nil for a blank and adds allow_nil: true instead. Mastodon's Webhook pairs presence: true with a bare url: true, which reports both errors for a blank address.

The validator accepts https://example.com, http://a.b/c?x=1, and http://localhost:3000. It rejects https://, javascript:alert(1), example.com, ftp://x.y, a space in the host, and a raw Unicode host such as https://bücher.example. Mastodon parses with Addressable and accepts that host; the standard library does not. An owner who needs internationalized hosts can switch the validator to Addressable.

Only http and https addresses with a host can be stored, so a URL shown as a property on show pages, list rows, public pages, and the Account page renders as link_to(value, value, target: "_blank", rel: "noopener nofollow ugc"). A blank optional value shows shared.values.missing. A URL Field chosen as the Primary Descriptor stays the page heading and the link to its record's own page. Mastodon's link formatter, Forem's profile header, and Discourse's user profile each open a user-entered address in a new tab with noopener; Mastodon and Discourse add nofollow, and Forem and Discourse add ugc for untrusted users. Hotwire Native opens the link in an in-app browser whether or not it targets a new window: iOS routes a new-window or other external link to SFSafariViewController through its new-window policy, and Android routes onCreateWindow to a Custom Tab.

A model example per Field checks an address, a blank value, and one rejected value against the :url message, and spec/validators/url_validator_spec.rb checks the validator's accepted and rejected values. Factories and request samples use https://example.com. A development seed keeps a URL literal only when the validator would accept it; otherwise it omits the value and lists the omission. An Entity whose model constant is UrlValidator would collide with the validator, and no Analyzer check covers that name yet.

Attachments

Support: see the support inventory row (repository-only).

Active Storage is the first-profile lowering for explicit uploaded Fields and Action Text embeds. These are profile consequences rather than per-Field choices. Shrine remains deferred until a demonstrated requirement such as resumable uploads justifies a second profile. See the attachment direction (repository-only).

An attachment or image Field lowers as the Rails attachment generator type would:

File access

Uploaded files follow the Policies of the pages that show them; the dated decision (repository-only) records why.

Download links expire, skip Cloudinary's CDN, and count bandwidth twice. Applications compiled before this lowering keep public upload assets. Size limits, attachment types, multiplicity, and cleanup remain unimplemented, and no GapSet entry lists them.

Image content type

Rails ships no attachment validators. 37signals' Fizzy checks avatar types by hand, and the unreleased Rails guide shows a hand-written validate method. A Plan with an image Field therefore gets app/validators/image_validator.rb, and each image Field declares validates :photo, image: true. The validator adds an :image error when a file is attached and Active Storage's image? is false, that is, when the file's content_type does not start with image. That is the image/* that the form's accept attribute asks the browser for. The locale adds errors.messages.image: "must be an image". The validator skips a missing file, so a blank required Field reports only "can't be blank".

Active Storage sets content_type when a file is assigned, before validation runs. It passes the bytes, the filename, and the declared type to Marcel, and a signature found in the bytes wins. A PDF, HTML, or zip file declared as image/png is therefore rejected. Active Storage uploads only after commit, so a rejected file never reaches Cloudinary. A file with no recognizable signature keeps the type that its upload declares, or else the type its filename suggests, so text sent as image/png passes. SVG is an image and passes; file access describes how markup types are served. The checkbox that removes a stored optional image does not skip the check, so a non-image chosen beside a checked box fails validation.

The active_storage_validations gem was set aside. Generated applications use one rule, which Rails' image? and Marcel already cover. The gem's spoofing protection needs the file or Magika command-line tool, which Core's Docker image does not install. A narrower list of formats would be a product choice, so it waits for Plan vocabulary.

A model example per image Field uploads the PNG fixture and expects no :image error, then uploads the text fixture and expects one, so an application whose only uploads are images also gets firstdraft-file.txt. spec/validators/image_validator_spec.rb checks the rule with an anonymous ActiveModel class and test doubles. DEPLOY.md tells the owner what the check leaves to them, as requirement F-5 asks: size limits, files with no recognizable signature, and cleanup of unattached files. An Entity whose model constant is ImageValidator would collide with the validator, and no Analyzer check covers that name yet.

Derived numeric values

The Plan can declare sum, average, minimum, and maximum over a named Association and source Field. A derived Field is not directly writable and must reflect changes to both source values and Association membership. Every derived Field needs a structured consumer. A detail-only average can remain a fresh Association AVG. An average used by a Scaffold collection, Predicate, Ordering, or Predicate-filtered Association needs a maintained queryable value. One isolated Compiler projection records a Counter Culture-maintained sum and count plus their quotient as a stored PostgreSQL-generated average. It explicitly records production_wiring_complete: false; neither part is selected profile output or generated-app behavior. Decision 0024 requires the target to compare a conventional Rails or common-gem result-column path and either keep that behavior there or record a narrow database-owned exception before generation. Counter Culture is not yet a profile pin. The semantic Field remains one Plan subject and adds no realization choice. A compatible index can follow from actual Predicate and Ordering use. Nullable sources, scoped membership, bulk writes, repair, and minimum or maximum still need proof before the Compiler claims support.

References marked “repository-only” name implementation or internal material outside this public guide. They are intentionally not links. Publishing a design does not prove its implementation.