Skip to content

Add dag version lookup on get task endpoint - #74365

Merged
bbovenzi merged 1 commit into
apache:mainfrom
astronomer:pr/version-aware-get-task
Oct 7, 2026
Merged

bbovenzi merged 1 commit into
apache:mainfrom
astronomer:pr/version-aware-get-task

Conversation

@bbovenzi

@bbovenzi bbovenzi commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

Add an optional dag_version_id on the get_task endpoint to be able to lookup task details depending on the version instead of only just the latest dag version.


Was generative AI tooling used to co-author this PR?
  • Yes (please specify the tool below)
    Claude Opus 5

  • Read the Pull Request Guidelines for more information. Note: commit author/co-author name and email in commits become permanently public when merged.
  • For fundamental code changes, an Airflow Improvement Proposal (AIP) is needed.
  • When adding dependency, check compliance with the ASF 3rd Party License Policy.
  • For significant user-facing changes create newsfragment: {pr_number}.significant.rst, in airflow-core/newsfragments. You can add this file in a follow-up commit after the PR is created so you know the PR number.

Comment thread airflow-core/src/airflow/api_fastapi/core_api/routes/public/tasks.py Outdated
Comment thread airflow-core/src/airflow/api_fastapi/core_api/routes/public/tasks.py Outdated
Comment thread airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_tasks.py Outdated
Comment thread airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_tasks.py Outdated
@bbovenzi
bbovenzi force-pushed the pr/version-aware-get-task branch from 4d00900 to b2d8592 Compare October 7, 2026 13:51
A task instance is explained by the Dag as it was when that instance ran,
but the endpoint always answered from the newest version. Anything
describing a past instance therefore reported a task that may since have
been edited, renamed or had its asset declarations changed.

The version is selected by number, matching the other public version
selectors, which also scopes the lookup to the Dag in the path. Omitting it
keeps the previous behaviour.
@bbovenzi

bbovenzi commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

Provider CI failures are unrelated

@bbovenzi
bbovenzi merged commit 05dec27 into apache:main Oct 7, 2026
153 of 155 checks passed
@bbovenzi
bbovenzi deleted the pr/version-aware-get-task branch October 7, 2026 20:18
bbovenzi added a commit to astronomer/airflow that referenced this pull request Oct 7, 2026
Three things shipped with the field-path scoping that a reviewer caught after
it merged.

The troubleshooting steps name `airflow plugins list`, which does not exist --
`plugins` takes no subcommand -- so anyone following them to find out why a
view is not scoped as expected gets an argparse error instead.

The operator section recommends leaving `operator` and `class_ref.class_name`
unqualified so each page reads its own record, which is right, but the
load-time check then reports the one the page lacks as a path that will make
the view "appear in more places than intended". That is untrue for this block:
the other path is what scopes this destination. Following the documentation
should not produce a warning saying the documentation is wrong. The check now
tells a path that names no field anywhere -- a misspelling -- apart from one
that names a real field on a record this destination does not have, and says
only what is true of each. The section leads with one view per destination,
which needs no such reasoning, and keeps the single block as the shorter form.

Validation also edited the plugin author's own `applies_to` dictionary to drop
null values. Harmless in isolation, but a plugin may pass one dictionary to
several views, and rewriting it is not this code's to do.

Which record an unqualified path is rooted at is also decided twice: once when
plugins load, to choose what to validate, and again in the browser, to choose
what to match. Nothing at runtime notices when the two tables disagree -- a
destination only one of them knows about makes every path on it unevaluable,
which shows the view everywhere instead of scoping it, and would surface later
as someone else's bug. A prek check compares them, so that drift fails before
it merges.

Scoping a task-level view on `task.*` judged historical task instances by the
Dag's definition today, so a view scoped to an operator stopped appearing on
the runs that actually used it as soon as the task changed. apache#74365 added a
version to the task endpoint, so the task is now read at the version the
instance ran. That costs a round trip on task instance routes, since the
version is not known until the instance arrives, and asking earlier would
fetch a task that has to be discarded.

The newsfragment was a documentation section rather than a release note, so it
is cut to what the release notes need and points at the docs for the rest.
Editing it trips `check-newsfragment-pr-number`, which expects any newsfragment
a PR touches to be named for that PR; renaming this one would credit the wrong
PR for the feature, so the check is skipped by label instead.
bbovenzi added a commit to astronomer/airflow that referenced this pull request Oct 7, 2026
Three things shipped with the field-path scoping that a reviewer caught after
it merged.

The troubleshooting steps name `airflow plugins list`, which does not exist --
`plugins` takes no subcommand -- so anyone following them to find out why a
view is not scoped as expected gets an argparse error instead.

The operator section recommends leaving `operator` and `class_ref.class_name`
unqualified so each page reads its own record, which is right, but the
load-time check then reports the one the page lacks as a path that will make
the view "appear in more places than intended". That is untrue for this block:
the other path is what scopes this destination. Following the documentation
should not produce a warning saying the documentation is wrong. The check now
tells a path that names no field anywhere -- a misspelling -- apart from one
that names a real field on a record this destination does not have, and says
only what is true of each. The section leads with one view per destination,
which needs no such reasoning, and keeps the single block as the shorter form.

A path that matches no field at all now withholds the view instead of loading
it. The browser cannot tell a misspelling from a field this page's record
simply does not have -- a block shared across destinations relies on the
latter being skipped -- so it skips both, and skipping widens the scope. A
typo therefore showed the view everywhere, the opposite of what its author
asked for. The response models are in hand when plugins load, so the two are
distinguishable there: a field no record has cannot be anything but a mistake,
while one a sibling record has is the shared-block pattern and still loads. A
view that disappears gets noticed; one on every page looks deliberate.

Validation also edited the plugin author's own `applies_to` dictionary to drop
null values. Harmless in isolation, but a plugin may pass one dictionary to
several views, and rewriting it is not this code's to do.

Which record an unqualified path is rooted at is also decided twice: once when
plugins load, to choose what to validate, and again in the browser, to choose
what to match. Nothing at runtime notices when the two tables disagree -- a
destination only one of them knows about makes every path on it unevaluable,
which shows the view everywhere instead of scoping it, and would surface later
as someone else's bug. A prek check compares them, so that drift fails before
it merges.

Scoping a task-level view on `task.*` judged historical task instances by the
Dag's definition today, so a view scoped to an operator stopped appearing on
the runs that actually used it as soon as the task changed. apache#74365 added a
version to the task endpoint, so the task is now read at the version the
instance ran. That costs a round trip on task instance routes, since the
version is not known until the instance arrives, and asking earlier would
fetch a task that has to be discarded.

The newsfragment was a documentation section rather than a release note, so it
is cut to what the release notes need and points at the docs for the rest.
Editing it trips `check-newsfragment-pr-number`, which expects any newsfragment
a PR touches to be named for that PR; renaming this one would credit the wrong
PR for the feature, so the check is skipped by label instead.
bbovenzi added a commit to astronomer/airflow that referenced this pull request Oct 7, 2026
Several things shipped with the field-path scoping in apache#74278 that review
caught after it merged, plus two fixes that depend on work landing since.

The troubleshooting steps name `airflow plugins list`, which does not exist --
`plugins` takes no subcommand -- so anyone following them to find out why a
view is not scoped as expected gets an argparse error instead.

The operator section recommends leaving `operator` and `class_ref.class_name`
unqualified so each page reads its own record, which is right, but the
load-time check then reports the one the page lacks as a path that will make
the view "appear in more places than intended". That is untrue for this block:
the other path is what scopes this destination. Following the documentation
should not produce a warning saying the documentation is wrong. The check now
tells a path that names no field anywhere -- a misspelling -- apart from one
that names a real field on a record this destination does not have, and says
only what is true of each. The section leads with one view per destination,
which needs no such reasoning, and keeps the single block as the shorter form.

A path that matches no field at all now withholds the view instead of loading
it. The browser cannot tell a misspelling from a field this page's record
simply does not have -- a block shared across destinations relies on the
latter being skipped -- so it skips both, and skipping widens the scope. A
typo therefore showed the view everywhere, the opposite of what its author
asked for. The response models are in hand when plugins load, so the two are
distinguishable there: a field no record has cannot be anything but a mistake,
while one a sibling record has is the shared-block pattern and still loads. A
view that disappears gets noticed; one on every page looks deliberate.

Validation also edited the plugin author's own `applies_to` dictionary to drop
null values. Harmless in isolation, but a plugin may pass one dictionary to
several views, and rewriting it is not this code's to do.

Which record an unqualified path is rooted at is also decided twice: once when
plugins load, to choose what to validate, and again in the browser, to choose
what to match. Nothing at runtime notices when the two tables disagree -- a
destination only one of them knows about makes every path on it unevaluable,
which shows the view everywhere instead of scoping it, and would surface later
as someone else's bug. A prek check compares them, so that drift fails before
it merges.

Scoping a task-level view on `task.*` judged historical task instances by the
Dag's definition today, so a view scoped to an operator stopped appearing on
the runs that actually used it as soon as the task changed. apache#74365 added a
version to the task endpoint, so the task is now read at the version the
instance ran. That costs a round trip on task instance routes, since the
version is not known until the instance arrives, and asking earlier would
fetch a task that has to be discarded.

The newsfragment was a documentation section rather than a release note, so it
is cut to what the release notes need and points at the docs for the rest.
Editing it trips `check-newsfragment-pr-number`, which expects any newsfragment
a PR touches to be named for that PR; renaming this one would credit the wrong
PR for the feature, so the check is skipped by label instead.
@bbovenzi bbovenzi mentioned this pull request Oct 7, 2026
1 task done
bbovenzi added a commit to astronomer/airflow that referenced this pull request Oct 8, 2026
Several things shipped with the field-path scoping in apache#74278 that review
caught after it merged, plus two fixes that depend on work landing since.

The troubleshooting steps name `airflow plugins list`, which does not exist --
`plugins` takes no subcommand -- so anyone following them to find out why a
view is not scoped as expected gets an argparse error instead.

The operator section recommends leaving `operator` and `class_ref.class_name`
unqualified so each page reads its own record, which is right, but the
load-time check then reports the one the page lacks as a path that will make
the view "appear in more places than intended". That is untrue for this block:
the other path is what scopes this destination. Following the documentation
should not produce a warning saying the documentation is wrong. The check now
tells a path that names no field anywhere -- a misspelling -- apart from one
that names a real field on a record this destination does not have, and says
only what is true of each. The section leads with one view per destination,
which needs no such reasoning, and keeps the single block as the shorter form.

A path that matches no field at all now withholds the view instead of loading
it. The browser cannot tell a misspelling from a field this page's record
simply does not have -- a block shared across destinations relies on the
latter being skipped -- so it skips both, and skipping widens the scope. A
typo therefore showed the view everywhere, the opposite of what its author
asked for. The response models are in hand when plugins load, so the two are
distinguishable there: a field no record has cannot be anything but a mistake,
while one a sibling record has is the shared-block pattern and still loads. A
view that disappears gets noticed; one on every page looks deliberate.

Validation also edited the plugin author's own `applies_to` dictionary to drop
null values. Harmless in isolation, but a plugin may pass one dictionary to
several views, and rewriting it is not this code's to do.

Which record an unqualified path is rooted at is also decided twice: once when
plugins load, to choose what to validate, and again in the browser, to choose
what to match. Nothing at runtime notices when the two tables disagree -- a
destination only one of them knows about makes every path on it unevaluable,
which shows the view everywhere instead of scoping it, and would surface later
as someone else's bug. A prek check compares them, so that drift fails before
it merges.

Scoping a task-level view on `task.*` judged historical task instances by the
Dag's definition today, so a view scoped to an operator stopped appearing on
the runs that actually used it as soon as the task changed. apache#74365 added a
version to the task endpoint, so the task is now read at the version the
instance ran. That costs a round trip on task instance routes, since the
version is not known until the instance arrives, and asking earlier would
fetch a task that has to be discarded.

The newsfragment was a documentation section rather than a release note, so it
is cut to what the release notes need and points at the docs for the rest.
Editing it trips `check-newsfragment-pr-number`, which expects any newsfragment
a PR touches to be named for that PR; renaming this one would credit the wrong
PR for the feature, so the check is skipped by label instead.
bbovenzi added a commit that referenced this pull request Oct 8, 2026
Several things shipped with the field-path scoping in #74278 that review
caught after it merged, plus two fixes that depend on work landing since.

The troubleshooting steps name `airflow plugins list`, which does not exist --
`plugins` takes no subcommand -- so anyone following them to find out why a
view is not scoped as expected gets an argparse error instead.

The operator section recommends leaving `operator` and `class_ref.class_name`
unqualified so each page reads its own record, which is right, but the
load-time check then reports the one the page lacks as a path that will make
the view "appear in more places than intended". That is untrue for this block:
the other path is what scopes this destination. Following the documentation
should not produce a warning saying the documentation is wrong. The check now
tells a path that names no field anywhere -- a misspelling -- apart from one
that names a real field on a record this destination does not have, and says
only what is true of each. The section leads with one view per destination,
which needs no such reasoning, and keeps the single block as the shorter form.

A path that matches no field at all now withholds the view instead of loading
it. The browser cannot tell a misspelling from a field this page's record
simply does not have -- a block shared across destinations relies on the
latter being skipped -- so it skips both, and skipping widens the scope. A
typo therefore showed the view everywhere, the opposite of what its author
asked for. The response models are in hand when plugins load, so the two are
distinguishable there: a field no record has cannot be anything but a mistake,
while one a sibling record has is the shared-block pattern and still loads. A
view that disappears gets noticed; one on every page looks deliberate.

Validation also edited the plugin author's own `applies_to` dictionary to drop
null values. Harmless in isolation, but a plugin may pass one dictionary to
several views, and rewriting it is not this code's to do.

Which record an unqualified path is rooted at is also decided twice: once when
plugins load, to choose what to validate, and again in the browser, to choose
what to match. Nothing at runtime notices when the two tables disagree -- a
destination only one of them knows about makes every path on it unevaluable,
which shows the view everywhere instead of scoping it, and would surface later
as someone else's bug. A prek check compares them, so that drift fails before
it merges.

Scoping a task-level view on `task.*` judged historical task instances by the
Dag's definition today, so a view scoped to an operator stopped appearing on
the runs that actually used it as soon as the task changed. #74365 added a
version to the task endpoint, so the task is now read at the version the
instance ran. That costs a round trip on task instance routes, since the
version is not known until the instance arrives, and asking earlier would
fetch a task that has to be discarded.

The newsfragment was a documentation section rather than a release note, so it
is cut to what the release notes need and points at the docs for the rest.
Editing it trips `check-newsfragment-pr-number`, which expects any newsfragment
a PR touches to be named for that PR; renaming this one would credit the wrong
PR for the feature, so the check is skipped by label instead.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants