Skip to content

CEP XXXX: A backwards-compatible repodata update strategy for repodata v3 - #146

Open
jaimergp wants to merge 24 commits into
conda:mainfrom
jaimergp:repodata-updates
Open

CEP XXXX: A backwards-compatible repodata update strategy for repodata v3#146
jaimergp wants to merge 24 commits into
conda:mainfrom
jaimergp:repodata-updates

Conversation

@jaimergp

@jaimergp jaimergp commented Jan 12, 2026

Copy link
Copy Markdown
Member

Checklist for submitter

Comment thread cep-XXXX.md Outdated
Comment thread cep-XXXX.md Outdated

@h-vetinari h-vetinari left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if "migrated" / migrated_at is the best naming. Aside from a question of what purpose the timestamp serves (see below), I think we should probably rename this to something simpler like since:. If we have to choose a verb, I'd rather we take something like "provide" rather than "migrate"; the latter is IMO not a good description for providing multiple repodata revisions simultaneously for an extended period of time.

For argument's sake, I think the below would be pretty self-explanatory

    "repodata_revisions": [
      {
        "revision": 3,
        "since": 1768249989751,     // 2026-01-12 20:33 UTC
        "dropped": 2234563200000,   // 2040-10-23 00:00 UTC
      },
      {
        "revision": 4,
        "since": 1842998400000,     // 2028-05-27 00:00 UTC
      },
      {
        "revision": 5,
        "since": 2053641600000,     // 2035-01-29 00:00 UTC
      }
    ]

Comment thread cep-XXXX.md Outdated
Comment thread cep-XXXX.md Outdated
Comment thread cep-XXXX.md Outdated
Comment thread cep-XXXX.md Outdated
Comment thread cep-XXXX.md Outdated
jaimergp and others added 3 commits March 9, 2026 18:03
Co-authored-by: H. Vetinari <h-vetinari@users.noreply.github.com>
Co-authored-by: H. Vetinari <h-vetinari@users.noreply.github.com>
Comment thread cep-XXXX.md
@jaimergp

Copy link
Copy Markdown
Member Author

@conda/steering-council, I'd like to start the RFC period for this CEP. It will be open until March 30th, EOD, AoE. Thank you!

@jaimergp

Copy link
Copy Markdown
Member Author

Looks like we have no further comments, nice 😎

Comment thread cep-XXXX.md Outdated
Comment on lines +45 to +46
* `oldest: int | None`: Optional. The timestamp (in milliseconds) of the oldest record published in this revision. If set to `None` or missing, the timestamp information is not available.
* `newest: int | None`: Optional. The timestamp (in milliseconds) of the newest record published in this revision. If set to `None` or missing, the timestamp information is not available.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could be a little clearer and say: "The Unix time in milliseconds" (a la CEP 34).

@dholth dholth Mar 30, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm unsure about tracking these numbers and the counts and propagating them back from individual shards generation to the shards index which has the info section. If we imagine a shards-only repodata, then the client would have to download all shards to double check package counts and timestamps.
Allowing conda-index to say "just pull all newer timestamps than X to the v3 section" would be the sort of implementation that I would be interested in, where conda-index would stay simple.
As a client, a boolean "client should be upgraded because there's repodata we don't understand?" is the most interesting information.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @dholth here.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made these values local to the file only. See this comment too.

Comment thread cep-XXXX.md Outdated

A new top-level field identified by the syntax `v{revision}` (where `revision` comes from `info.repodata_revisions[*].revision`) MUST map to a dictionary whose schema is presented in the relevant CEP.

The CEP MUST also specify how to identify whether a given record belongs in the newer version, or can be added to the previous ones (e.g. a new field extending CEP 20's `info/index.json`)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does "The CEP" here mean this CEP, or later "implementation" CEPs making repodata revisions under this CEP?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is hopefully clearer now, PTAL 🙏

Comment thread cep-XXXX.md Outdated

A repodata revision introduces backwards incompatible features in a way that does not disrupt existing metadata. To do so, a new CEP MUST be proposed, following these guidelines below.

A new item MUST be added to the `info.repodata_revisions` array, that MUST list the revisions found in the repodata file as dictionaries with the following schema:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason to make this an array rather than a dict-of-dicts, with vN as the key and the other fields specified below as sub-dicts; e.g.,

"info": {
   ...
   "repodata_revisions": {
      "v3": {
        "n_packages": 42,
        "oldest": ....,
        "newest": ....
      },
      "v4": {
        "n_packages": 42,
        "oldest": ....,
        "newest": ....
      },
   }
   ...
}

A big issue I can see with repodata_revisions an array is that it (by itself) imposes no uniqueness constraint on revision, which leads us to have to answer, "what should tools do if they see multiple {"revision": 3, ...} in the array?"

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See e65a5c5

Comment thread cep-XXXX.md Outdated
A new item MUST be added to the `info.repodata_revisions` array, that MUST list the revisions found in the repodata file as dictionaries with the following schema:

* `revision: int`: Required. The integer identifying the revision.
* `n_packages: int`: Required. The number of packages available in this revision.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is an required element, we should specify if tools MUST do anything particular with this data (e.g., verify the number of packages in the vN field), or is this field only exists for tools to use as they see fit (e.g., making package count verification optional).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe we should make it optional? I think it's purely informational

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See e65a5c5

Comment thread cep-XXXX.md Outdated
Comment on lines +45 to +46
* `oldest: int | None`: Optional. The timestamp (in milliseconds) of the oldest record published in this revision. If set to `None` or missing, the timestamp information is not available.
* `newest: int | None`: Optional. The timestamp (in milliseconds) of the newest record published in this revision. If set to `None` or missing, the timestamp information is not available.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, not sure if we need to explicitly say these here, but:

  • I assume timestamp ranges for various repodata revisions are allowed to overlap? E.g., the existing (v1/v2) packages.conda section can continue to publish packages, independent of any v3 date range.
  • If newest and oldest are both present and not None, newest must be greater than or equal to oldest.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes sense

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's implied by the commonly understood meaning of "oldest" and "newest". Still, I reworded this part to ensure that it matches actual metadata in the file.

Comment thread cep-XXXX.md
baszalmstra pushed a commit to baszalmstra/rattler that referenced this pull request Jun 3, 2026
Follow the CEP draft (conda/ceps#146) into the in-memory representation:
the top-level info.repodata_revisions (and the sharded index equivalent)
is now an IndexMap keyed by RepodataRevision, mirroring the dictionary
structure that encodes revision uniqueness instead of a Vec that allowed
duplicates and redundantly repeated the revision in each element.

- Add the RepodataRevisions map alias and a RepodataRevisionMetadata value
  struct; RepodataRevisionInfo is kept as the flattened (revision + metadata)
  unit used for indexer input and reporter messages, with from_metadata/
  metadata helpers to convert between the two.
- Update the gateway accessors (returning &RepodataRevisions, with a shared
  empty-map helper) and the indexer to produce the map.

The wire format is unchanged from the previous commit (a vN-keyed dict).
baszalmstra pushed a commit to baszalmstra/rattler that referenced this pull request Jun 4, 2026
Update the top-level info.repodata_revisions (and the sharded index
equivalent) to match the latest CEP draft
(conda/ceps#146), which describes it as a
dictionary keyed by revision identifier (e.g. "v3") instead of a list.
The in-memory representation is a revision-keyed map so a revision cannot
appear twice.

The Python indexing bindings accept the same dictionary shape for
repodata_revisions, with timestamps given as datetime values for
consistency with the rest of the API.

Includes a regression test that reads the dictionary form from a repodata
file in the test data and asserts it parses correctly.

https://claude.ai/code/session_01ModY1fX2YqL6ULMbJtfqWa
Comment thread cep-XXXX.md Outdated
Comment on lines +68 to +72
- The MatchSpec strings mentioned in the fields `depends`, `constrains` and the lists of strings within `extra_depends` groups:
- MUST set the `name` field to an exact string (no globbing allowed).
- MAY set the fields: `version`, `build`, `build_number`, CEP 43's `when`, CEP 44 `extra`, CEP 45 `flags`.
- MUST NOT set any other fields.
- MUST be represented with the `name` + square-brackets form (e.g. `name[version="1.2.*",build_number=0]`)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewers, please pay attention to this part, since it restricts which MatchSpec strings can be used.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now with v3 repodata we are generating with conda-index, version doesn't appear in square brackets. I understand that this CEP as worded would require pytest[version=">=2.7.2"] instead of pytest>=2.7.2. Is that a correct understanding and can you help me understand the motivation to make the syntax more restrictive? Thanks!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also curious about this!

@jaimergp jaimergp Jul 26, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-square brackets syntax can be very ambiguous (especially when build strings are also added). I want to move away from that syntax in stored repodata (and leave it as syntactic sugar for user input only). Users can still add whatever in the recipes (that bit is not specified here), but repodata creation tools (indexing) must canonicalize the representation in the repodata for clarity.

Is that a good enough reason?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread cep-XXXX.md Outdated
Comment thread cep-XXXX.md Outdated
Comment thread cep-XXXX.md Outdated
Comment thread cep-XXXX.md Outdated
Comment thread cep-XXXX.md Outdated
Comment on lines +68 to +72
- The MatchSpec strings mentioned in the fields `depends`, `constrains` and the lists of strings within `extra_depends` groups:
- MUST set the `name` field to an exact string (no globbing allowed).
- MAY set the fields: `version`, `build`, `build_number`, CEP 43's `when`, CEP 44 `extra`, CEP 45 `flags`.
- MUST NOT set any other fields.
- MUST be represented with the `name` + square-brackets form (e.g. `name[version="1.2.*",build_number=0]`)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now with v3 repodata we are generating with conda-index, version doesn't appear in square brackets. I understand that this CEP as worded would require pytest[version=">=2.7.2"] instead of pytest>=2.7.2. Is that a correct understanding and can you help me understand the motivation to make the syntax more restrictive? Thanks!

@jaimergp

jaimergp commented Aug 5, 2026

Copy link
Copy Markdown
Member Author

@conda/steering-council, the vote for this CEP will start soon, like in 24-48h. If you have any comments, this is your last chance. Thanks!

@jaimergp

jaimergp commented Aug 6, 2026

Copy link
Copy Markdown
Member Author

Dear @conda/steering-council,

The vote for this CEP has started. It will be open for two weeks, until August 20th, 2026, 23:59 Anywhere on Earth. This time period has been chosen to make it eligible for time-out rules. As an Enhancement Proposal vote, it requires 60% affirmative votes to pass.

To vote, please mark the relevant checkbox under your username:

@wolfv

wolfv commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Thanks to everyone who chimed in! Really really excited to see this moving forward!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

vote Voting following governance policy

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants