CEP XXXX: A backwards-compatible repodata update strategy for repodata v3 - #146
CEP XXXX: A backwards-compatible repodata update strategy for repodata v3#146jaimergp wants to merge 24 commits into
v3#146Conversation
h-vetinari
left a comment
There was a problem hiding this comment.
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
}
]Co-authored-by: H. Vetinari <h-vetinari@users.noreply.github.com>
5090659 to
c58d212
Compare
|
@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! |
|
Looks like we have no further comments, nice 😎 |
| * `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. |
There was a problem hiding this comment.
We could be a little clearer and say: "The Unix time in milliseconds" (a la CEP 34).
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
I made these values local to the file only. See this comment too.
|
|
||
| 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`) |
There was a problem hiding this comment.
Does "The CEP" here mean this CEP, or later "implementation" CEPs making repodata revisions under this CEP?
There was a problem hiding this comment.
This is hopefully clearer now, PTAL 🙏
|
|
||
| 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: |
There was a problem hiding this comment.
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?"
| 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. |
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
maybe we should make it optional? I think it's purely informational
| * `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. |
There was a problem hiding this comment.
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.condasection 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.
There was a problem hiding this comment.
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.
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).
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
…e` field, rework specification schema explainer, restrict which type of MatchSpec is allowed
| - 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]`) |
There was a problem hiding this comment.
Reviewers, please pay attention to this part, since it restricts which MatchSpec strings can be used.
There was a problem hiding this comment.
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!
There was a problem hiding this comment.
Also curious about this!
There was a problem hiding this comment.
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?
| - 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]`) |
There was a problem hiding this comment.
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!
Co-authored-by: Dan Yeaw <dan@yeaw.me>
|
@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! |
|
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:
|
|
Thanks to everyone who chimed in! Really really excited to see this moving forward! |
Checklist for submitter
v3.cep-0000.mdnamedcep-XXXX.mdin the root level.