Ok. I think those were accidentally uncommitted binaries - and instead of
rc3, I still had the old rc2 :(
I think I missed an error when copying files.

It's fantastic that we have reproducibility checks - otherwise we might not
have found it. Thanks for flagging it Jens!

It should all be fixed now. The PyPI packages were correct.

Let me restart the voting. The new date for the Vote passing is Monday,
2026-04-27 23:59 UTC.

Consider this my (binding) +1.







On Wed, Apr 22, 2026 at 8:13 PM Jarek Potiuk <[email protected]> wrote:

> Thanks. Will take a look !
>
> On Wed, Apr 22, 2026 at 8:12 PM Jens Scheffler <[email protected]>
> wrote:
>
>> Hi Jarek,
>>
>> i attempted to run PMC Checks but I fail in reproducibility - so until I
>> know I'd do something wrong I'd need to vote a -1:
>>
>> SVN: revision 83981.
>>
>> Branch/Git: tag: airflow-ctl/0.1.4rc3
>> ca53e01b3c8bb00a3ca697b508ab52cdd28f5e68
>>
>> Checking if apache_airflow_ctl-0.1.4-py3-none-any.whl is the same as
>>
>> /home/jscheffl/Workspace/airflow/dist/apache_airflow_ctl-0.1.4-py3-none-any.whl
>> Binary files apache_airflow_ctl-0.1.4-py3-none-any.whl and
>> /home/jscheffl/Workspace/airflow/dist/apache_airflow_ctl-0.1.4-py3-none-any.whl
>>
>> differ
>>
>> Checking if apache_airflow_ctl-0.1.4-source.tar.gz is the same as
>>
>> /home/jscheffl/Workspace/airflow/dist/apache_airflow_ctl-0.1.4-source.tar.gz
>> Binary files apache_airflow_ctl-0.1.4-source.tar.gz and
>> /home/jscheffl/Workspace/airflow/dist/apache_airflow_ctl-0.1.4-source.tar.gz
>>
>> differ
>>
>> Checking if apache_airflow_ctl-0.1.4.tar.gz is the same as
>> /home/jscheffl/Workspace/airflow/dist/apache_airflow_ctl-0.1.4.tar.gz
>> Binary files apache_airflow_ctl-0.1.4.tar.gz and
>> /home/jscheffl/Workspace/airflow/dist/apache_airflow_ctl-0.1.4.tar.gz
>> differ
>>
>> Did I pick the wrong package or branch?
>>
>> For the WHL file diffoscope tells me:
>>
>>   * a lot of file meta data differences
>>       o -rw-r--r--  2.0 unx     1705 b- defN 26-Apr-13 12:48
>>         airflowctl/exceptions.py
>>         to
>>       o -rw-r--r--  2.0 unx     1705 b- defN 26-Apr-20 11:13
>>         airflowctl/exceptions.py
>>   * Diff in api/datamodels/generated.py
>>
>> ├── airflowctl/api/datamodels/generated.py
>> │ @@ -169,15 +169,14 @@
>> │          bool | None,
>> │          Field(
>> │              description="(Experimental) Run on the latest bundle
>> version of the dag after clearing the task instances.",
>> │              title="Run On Latest Version",
>> │          ),
>> │      ] = False
>> │      prevent_running_task: Annotated[bool | None, Field(title="Prevent
>> Running Task")] = False
>> │ -    note: Annotated[Note | None, Field(title="Note")] = None
>> │
>> │
>> │  class Value(RootModel[list]):
>> │      root: Annotated[list, Field(max_length=2, min_length=2,
>> title="Value")]
>> │
>> │
>> │  class ConfigOption(BaseModel):
>> │ @@ -284,21 +283,14 @@
>> │      """
>> │
>> │      model_config = ConfigDict(
>> │          extra="forbid",
>> │      )
>> │      dry_run: Annotated[bool | None, Field(title="Dry Run")] = True
>> │      only_failed: Annotated[bool | None, Field(title="Only Failed")] =
>> False
>> │ -    only_new: Annotated[
>> │ -        bool | None,
>> │ -        Field(
>> │ -            description="Only queue newly added tasks in the latest
>> DAG version without clearing existing tasks.",
>> │ -            title="Only New",
>> │ -        ),
>> │ -    ] = False
>> │      run_on_latest_version: Annotated[
>> │          bool | None,
>> │          Field(
>> │              description="(Experimental) Run on the latest bundle
>> version of the Dag after clearing the Dag Run.",
>> │              title="Run On Latest Version",
>> │          ),
>> │      ] = False
>> │ @@ -398,15 +390,14 @@
>> │      """
>> │      Class with DagRun types.
>> │      """
>> │
>> │      BACKFILL = "backfill"
>> │      SCHEDULED = "scheduled"
>> │      MANUAL = "manual"
>> │ -    OPERATOR_TRIGGERED = "operator_triggered"
>> │      ASSET_TRIGGERED = "asset_triggered"
>> │      ASSET_MATERIALIZATION = "asset_materialization"
>> │
>> │
>> │  class DagScheduleAssetReference(BaseModel):
>> │      """
>> │      DAG schedule reference serializer for assets.
>> │ @@ -643,23 +634,14 @@
>> │      logical_date: Annotated[datetime | None, Field(title="Logical
>> Date")] = None
>> │      run_after: Annotated[datetime | None, Field(title="Run After")] =
>> None
>> │      conf: Annotated[dict[str, Any] | None, Field(title="Conf")] = None
>> │      note: Annotated[str | None, Field(title="Note")] = None
>> │      partition_key: Annotated[str | None, Field(title="Partition
>> Key")] = None
>> │
>> │
>> │ -class NewTaskResponse(BaseModel):
>> │ -    """
>> │ -    Lightweight response for new tasks that don't have TaskInstances
>> yet.
>> │ -    """
>> │ -
>> │ -    task_id: Annotated[str, Field(title="Task Id")]
>> │ -    task_display_name: Annotated[str, Field(title="Task Display Name")]
>> │ -
>> │ -
>> │  class PluginImportErrorResponse(BaseModel):
>> │      """
>> │      Plugin Import Error serializer for responses.
>> │      """
>> │
>> │      source: Annotated[str, Field(title="Source")]
>> │      error: Annotated[str, Field(title="Error")]
>> │ @@ -1144,15 +1126,15 @@
>> │      model_config = ConfigDict(
>> │          extra="forbid",
>> │      )
>> │      dag_id: Annotated[str, Field(title="Dag Id")]
>> │      from_date: Annotated[datetime, Field(title="From Date")]
>> │      to_date: Annotated[datetime, Field(title="To Date")]
>> │      run_backwards: Annotated[bool | None, Field(title="Run
>> Backwards")] = False
>> │ -    dag_run_conf: Annotated[dict[str, Any] | None, Field(title="Dag
>> Run Conf")] = None
>> │ +    dag_run_conf: Annotated[dict[str, Any] | None, Field(title="Dag
>> Run Conf")] = {}
>> │      reprocess_behavior: ReprocessBehavior | None = "none"
>> │      max_active_runs: Annotated[int | None, Field(title="Max Active
>> Runs")] = 10
>> │      run_on_latest_version: Annotated[bool | None, Field(title="Run On
>> Latest Version")] = True
>> │
>> │
>> │  class BackfillResponse(BaseModel):
>> │      """
>> │ @@ -1390,15 +1372,14 @@
>> │      bundle_version: Annotated[str | None, Field(title="Bundle
>> Version")] = None
>> │      relative_fileloc: Annotated[str | None, Field(title="Relative
>> Fileloc")] = None
>> │      fileloc: Annotated[str, Field(title="Fileloc")]
>> │      description: Annotated[str | None, Field(title="Description")] =
>> None
>> │      timetable_summary: Annotated[str | None, Field(title="Timetable
>> Summary")] = None
>> │      timetable_description: Annotated[str | None,
>> Field(title="Timetable Description")] = None
>> │      timetable_partitioned: Annotated[bool, Field(title="Timetable
>> Partitioned")]
>> │ -    timetable_periodic: Annotated[bool, Field(title="Timetable
>> Periodic")]
>> │      tags: Annotated[list[DagTagResponse], Field(title="Tags")]
>> │      max_active_tasks: Annotated[int, Field(title="Max Active Tasks")]
>> │      max_active_runs: Annotated[int | None, Field(title="Max Active
>> Runs")] = None
>> │      max_consecutive_failed_dag_runs: Annotated[int, Field(title="Max
>> Consecutive Failed Dag Runs")]
>> │      has_task_concurrency_limits: Annotated[bool, Field(title="Has
>> Task Concurrency Limits")]
>> │      has_import_errors: Annotated[bool, Field(title="Has Import
>> Errors")]
>> │      next_dagrun_logical_date: Annotated[datetime | None,
>> Field(title="Next Dagrun Logical Date")] = None
>> │ @@ -1423,17 +1404,14 @@
>> │      template_search_path: Annotated[list[str] | None,
>> Field(title="Template Search Path")] = None
>> │      timezone: Annotated[str | None, Field(title="Timezone")] = None
>> │      last_parsed: Annotated[datetime | None, Field(title="Last
>> Parsed")] = None
>> │      default_args: Annotated[dict[str, Any] | None,
>> Field(title="Default Args")] = None
>> │      owner_links: Annotated[dict[str, str] | None, Field(title="Owner
>> Links")] = None
>> │      is_favorite: Annotated[bool | None, Field(title="Is Favorite")] =
>> False
>> │      active_runs_count: Annotated[int | None, Field(title="Active Runs
>> Count")] = 0
>> │ -    is_backfillable: Annotated[
>> │ -        bool, Field(description="Whether this DAG's schedule supports
>> backfilling.", title="Is Backfillable")
>> │ -    ]
>> │      file_token: Annotated[str, Field(description="Return file
>> token.", title="File Token")]
>> │      concurrency: Annotated[
>> │          int,
>> │          Field(
>> │              description="Return max_active_tasks as
>> concurrency.\n\nDeprecated: Use max_active_tasks instead.",
>> │              title="Concurrency",
>> │          ),
>> │ @@ -1459,15 +1437,14 @@
>> │      bundle_version: Annotated[str | None, Field(title="Bundle
>> Version")] = None
>> │      relative_fileloc: Annotated[str | None, Field(title="Relative
>> Fileloc")] = None
>> │      fileloc: Annotated[str, Field(title="Fileloc")]
>> │      description: Annotated[str | None, Field(title="Description")] =
>> None
>> │      timetable_summary: Annotated[str | None, Field(title="Timetable
>> Summary")] = None
>> │      timetable_description: Annotated[str | None,
>> Field(title="Timetable Description")] = None
>> │      timetable_partitioned: Annotated[bool, Field(title="Timetable
>> Partitioned")]
>> │ -    timetable_periodic: Annotated[bool, Field(title="Timetable
>> Periodic")]
>> │      tags: Annotated[list[DagTagResponse], Field(title="Tags")]
>> │      max_active_tasks: Annotated[int, Field(title="Max Active Tasks")]
>> │      max_active_runs: Annotated[int | None, Field(title="Max Active
>> Runs")] = None
>> │      max_consecutive_failed_dag_runs: Annotated[int, Field(title="Max
>> Consecutive Failed Dag Runs")]
>> │      has_task_concurrency_limits: Annotated[bool, Field(title="Has
>> Task Concurrency Limits")]
>> │      has_import_errors: Annotated[bool, Field(title="Has Import
>> Errors")]
>> │      next_dagrun_logical_date: Annotated[datetime | None,
>> Field(title="Next Dagrun Logical Date")] = None
>> │ @@ -1476,17 +1453,14 @@
>> │      ] = None
>> │      next_dagrun_data_interval_end: Annotated[
>> │          datetime | None, Field(title="Next Dagrun Data Interval End")
>> │      ] = None
>> │      next_dagrun_run_after: Annotated[datetime | None,
>> Field(title="Next Dagrun Run After")] = None
>> │      allowed_run_types: Annotated[list[DagRunType] | None,
>> Field(title="Allowed Run Types")] = None
>> │      owners: Annotated[list[str], Field(title="Owners")]
>> │ -    is_backfillable: Annotated[
>> │ -        bool, Field(description="Whether this DAG's schedule supports
>> backfilling.", title="Is Backfillable")
>> │ -    ]
>> │      file_token: Annotated[str, Field(description="Return file
>> token.", title="File Token")]
>> │
>> │
>> │  class DAGRunPatchBody(BaseModel):
>> │      """
>> │      DAG Run Serializer for PATCH requests.
>> │      """
>> │ @@ -1954,23 +1928,14 @@
>> │      entities: Annotated[
>> │          list[str | BulkTaskInstanceBody],
>> │          Field(description="A list of entity id/key or entity objects
>> to be deleted.", title="Entities"),
>> │      ]
>> │      action_on_non_existence: BulkActionNotOnExistence | None = "fail"
>> │
>> │
>> │ -class ClearTaskInstanceCollectionResponse(BaseModel):
>> │ -    """
>> │ -    Response for clear dag run dry run, which may contain new tasks
>> without full TaskInstance data.
>> │ -    """
>> │ -
>> │ -    task_instances: Annotated[list[TaskInstanceResponse |
>> NewTaskResponse], Field(title="Task Instances")]
>> │ -    total_entries: Annotated[int, Field(title="Total Entries")]
>> │ -
>> │ -
>> │  class DAGCollectionResponse(BaseModel):
>> │      """
>> │      DAG Collection serializer for responses.
>> │      """
>> │
>> │      dags: Annotated[list[DAGResponse], Field(title="Dags")]
>> │      total_entries: Annotated[int, Field(title="Total Entries")]
>> │ @@ -2070,46 +2035,19 @@
>> │
>> │      tasks: Annotated[list[TaskResponse], Field(title="Tasks")]
>> │      total_entries: Annotated[int, Field(title="Total Entries")]
>> │
>> │
>> │  class TaskInstanceCollectionResponse(BaseModel):
>> │      """
>> │ -    Task instance collection response supporting both offset and
>> cursor pagination.
>> │ -
>> │ -    A single flat model is used instead of a discriminated union
>> │ -    (``Annotated[Offset | Cursor, Field(discriminator=...)]``) because
>> │ -    the OpenAPI ``oneOf`` + ``discriminator`` construct is not handled
>> │ -    correctly by ``@hey-api/openapi-ts`` /
>> ``@7nohe/openapi-react-query-codegen``:
>> │ -    return types degrade to ``unknown`` in JSDoc and can produce
>> │ -    incorrect TypeScript types (see hey-api/openapi-ts#1613, #3270).
>> │ +    Task Instance Collection serializer for responses.
>> │      """
>> │
>> │      task_instances: Annotated[list[TaskInstanceResponse],
>> Field(title="Task Instances")]
>> │ -    total_entries: Annotated[
>> │ -        int | None,
>> │ -        Field(
>> │ -            description="Total number of matching items. Populated
>> for offset pagination, ``null`` when using cursor pagination.",
>> │ -            title="Total Entries",
>> │ -        ),
>> │ -    ] = None
>> │ -    next_cursor: Annotated[
>> │ -        str | None,
>> │ -        Field(
>> │ -            description="Token pointing to the next page. Populated
>> for cursor pagination, ``null`` when using offset pagination or when
>> there is no next page.",
>> │ -            title="Next Cursor",
>> │ -        ),
>> │ -    ] = None
>> │ -    previous_cursor: Annotated[
>> │ -        str | None,
>> │ -        Field(
>> │ -            description="Token pointing to the previous page.
>> Populated for cursor pagination, ``null`` when using offset pagination
>> or when on the first page.",
>> │ -            title="Previous Cursor",
>> │ -        ),
>> │ -    ] = None
>> │ +    total_entries: Annotated[int, Field(title="Total Entries")]
>> │
>> │
>> │  class TaskInstanceHistoryCollectionResponse(BaseModel):
>> │      """
>> │      TaskInstanceHistory Collection serializer for responses.
>> │      """
>>
>> On 22.04.26 01:55, Jarek Potiuk wrote:
>> > The release candidate for **Apache Airflow Ctl**: 0.1.4rc3 is now
>> > available for testing!
>> >
>> > This email is calling for a vote on the release, which will last at
>> least until
>> > Friday, 2026-04-24 23:59 UTC and until 3 binding +1 votes have been
>> received.
>> >
>> > Consider this my +1 (binding) vote.
>> >
>> > The apache-airflow-ctl 0.1.4rc3 package is available at:
>> > https://dist.apache.org/repos/dist/dev/airflow/airflow-ctl/0.1.4rc3/
>> >
>> > The "apache-airflow-ctl" packages are:
>> >
>> >     - *apache_airflow_ctl-0.1.4-source.tar.gz* is a source release that
>> comes
>> >       with INSTALL instructions.
>> >     - *apache_airflow_ctl-0.1.4.tar.gz* is the binary Python "sdist"
>> release.
>> >     - *apache_airflow_ctl-0.1.4-py3-none-any.whl* is the binary Python
>> wheel
>> >       "binary" release.
>> >
>> > Public keys are available at:
>> > https://dist.apache.org/repos/dist/release/airflow/KEYS
>> >
>> > Please vote accordingly:
>> >
>> > [ ] +1 approve
>> > [ ] +0 no opinion
>> > [ ] -1 disapprove with the reason
>> >
>> > Only votes from PMC members are binding, but all members of the
>> community are
>> > encouraged to test the release and vote with "(non-binding)".
>> >
>> > The test procedure for PMC members is described in:
>> >
>> https://github.com/apache/airflow/blob/main/dev/README_RELEASE_AIRFLOWCTL.md#verify-the-release-candidate-by-pmc-members
>> >
>> > The test procedure for contributors and members of the community who
>> would
>> > like to test this RC is described in:
>> >
>> https://github.com/apache/airflow/blob/main/dev/README_RELEASE_AIRFLOWCTL.md#verify-the-release-candidate-by-contributors
>> >
>> > Please note that the version number excludes the 'rcX' string, so it's
>> now
>> > simply 0.1.4 for the apache-airflow-ctl package. This will allow us to
>> rename
>> > the artifact without modifying the artifact checksums when we actually
>> release.
>> >
>> > Testing status issue:
>> > https://github.com/apache/airflow/issues/65643
>> >
>> > *Docs* (for preview):
>> >
>> https://airflow.staged.apache.org/docs/apache-airflow-ctl/0.1.4/index.html
>> >
>> > *Release Notes*:
>> >
>> https://github.com/apache/airflow/blob/airflow-ctl/0.1.4rc3/airflow-ctl/RELEASE_NOTES.rst
>> >
>> > *Testing Instructions using PyPI*:
>> >
>> > The packages are available in PyPI:
>> > https://pypi.org/project/apache-airflow-ctl/0.1.4rc3/
>> >
>> > You can build a virtualenv that installs this and other required
>> packages
>> > like this:
>> >
>> >      uv venv
>> >      uv pip install -U apache-airflow-ctl==0.1.4rc3
>> >
>> > Regards,
>> > Jarek
>> >
>> > ---------------------------------------------------------------------
>> > To unsubscribe, e-mail:[email protected]
>> > For additional commands, e-mail:[email protected]
>> >
>
>

Reply via email to