Skip to content

#232: Airflow SignalForgeGenerateOperator - #241

Merged
wjduenow merged 10 commits into
devfrom
feature/232-generate-operator
Jun 16, 2026
Merged

wjduenow merged 10 commits into
devfrom
feature/232-generate-operator

Conversation

@wjduenow

@wjduenow wjduenow commented Jun 16, 2026

Copy link
Copy Markdown
Owner

Summary

Implements #232SignalForgeGenerateOperator (epic #228, builds on #231). Plan: plans/super/232-generate-operator.md (Phase: devolved → implemented).

All 7 plan stories landed + Quality Gate + a PR-review pass (CodeRabbit + Copilot). See the "Implementation landed" and "PR Review Summary" comments for detail.

Changes

  • src/signalforge/airflow/operators.py — real operator (deferred construction; airflow-free import, airflow-required construction), pure helpers, execute() wiring.
  • examples/airflow/signalforge_generate_operator_dag.py — operator example DAG.
  • tests/airflow/ — ungated pure-helper tests (100% covered) + gated execute()/DAG-parse/render tests.
  • docs/airflow-ops.md, .claude/rules/airflow-integration.md — operator docs + conventions.

Testing

  • Default suite: 3927 passed, ruff/format/pyright clean, operators.py 100% covered.
  • Gated certification vs real Airflow 2.10.4 (.venv-airflow): 22 passed, 1 skipped (live-warehouse e2e needs SF_RUN_BQ).

Compounding update

  • New rule section .claude/rules/airflow-integration.md § "SignalForgeGenerateOperator" + memory signalforge-airflow-operator-pattern.

Summary by CodeRabbit

  • New Features

    • Added SignalForgeGenerateOperator for Airflow drift monitoring, supporting single-model runs and --select batch workflows with per-model execution and aggregated outcomes.
    • Added on_flagged task behavior to control fail/skip/succeed based on flagged artifacts, plus read-only “dry-run” semantics for write prevention.
  • Documentation

    • Updated Airflow integration docs with the operator as the recommended integration surface, including usage, parameter mappings, --select/aggregation semantics, and updated caveats.
    • Added a new example DAG demonstrating the operator-first pattern.
  • Tests

    • Added operator and helper unit tests covering execution, validation, selector resolution, argv construction, and batch aggregation behavior.

@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9d10bf0c-bb7f-4f34-8c09-85926f7b1a02

📥 Commits

Reviewing files that changed from the base of the PR and between c7bf7b0 and 73dbf73.

📒 Files selected for processing (5)
  • docs/airflow-ops.md
  • src/signalforge/airflow/operators.py
  • tests/airflow/test_operators.py
  • tests/airflow/test_operators_helpers.py
  • tests/airflow/test_skeleton.py
✅ Files skipped from review due to trivial changes (1)
  • docs/airflow-ops.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • tests/airflow/test_skeleton.py
  • tests/airflow/test_operators_helpers.py
  • tests/airflow/test_operators.py
  • src/signalforge/airflow/operators.py

📝 Walkthrough

Walkthrough

Replaces the SignalForgeGenerateOperator skeleton stub with a full implementation. The operator supports single-model and --select batch execution, lazy Airflow-free import via PEP 562 __getattr__, on_flagged task-state mapping, per-model XCom aggregation, and AirflowConfigError translation for manifest/selector failures. Accompanied by an example DAG, ungated helper tests, gated execute tests, and updated documentation.

Changes

SignalForgeGenerateOperator Full Implementation

Layer / File(s) Summary
Design plan and AI rules update
plans/super/232-generate-operator.md, .claude/rules/airflow-integration.md
Adds the Super Plan #232 document capturing DEC-001..011 engineering decisions, US-001..007 work breakdown, and compliance gate checklist. Updates AI rules to record operator landing and structural contracts.
Airflow-free pure helper functions
src/signalforge/airflow/operators.py
Adds _build_generate_argv (parameter→argv mapping, write/dry-run), _validate_operator_config (project_dir, mutual exclusivity, injection guards, on_flagged), _resolve_select_models (manifest load + selector parse + AirflowConfigError mapping), _aggregate_batch_result (max exit_code, summed counters, averaged grades, cleared sidecars), and _without_sidecar_paths helper.
Lazy operator class construction and PEP 562 resolution
src/signalforge/airflow/operators.py
Adds _GenerateOperatorAirflowMissing placeholder, _make_generate_operator_class (dynamically builds real BaseOperator subclass with template_fields, __init__, and execute()), _get_generate_operator_class (cached find_spec check), and module-level __getattr__ for lazy public name resolution.
Example operator DAG
examples/airflow/signalforge_generate_operator_dag.py
Adds a new example DAG with env-var→Airflow-Variable→default config resolution, parse-time on_flagged validation, schedule=None with templated params, and SignalForgeGenerateOperator as drift_monitor with write=False.
Ungated helper tests
tests/airflow/test_operators_helpers.py
Adds fully ungated tests covering _build_generate_argv, _validate_operator_config, _resolve_select_models, _aggregate_batch_result, and _without_sidecar_paths with deterministic argv construction, parameter validation, selector error mapping, and batch aggregation semantics.
Skeleton test update
tests/airflow/test_skeleton.py
Updates skeleton test to verify Airflow-free import of the operator name and ModuleNotFoundError/ImportError on construction when Airflow is absent.
Gated execute() tests
tests/airflow/test_operators.py
Adds Airflow-gated tests for single-model and batch execute paths, on_flagged exception routing, argv shape, forced cache_scope=project, batch XCom shape, aggregate exit-code outcome, and construction-time fast-fail validation.
DAG parse and template rendering tests
tests/airflow/test_dag_parse.py
Extends DAG parse tests with parameterized helper, operator example DAG parse test, and render_template_fields verification for templated select and as_of fields.
User-facing documentation updates
docs/airflow-ops.md
Updates v0.7 status to name SignalForgeGenerateOperator as recommended, adds full operator reference section (parameter table, write/dry-run, on_flagged, invocation modes, batch XCom shape), and updates caveats.

Sequence Diagram(s)

sequenceDiagram
  participant DAG as Airflow DAG
  participant Op as SignalForgeGenerateOperator.execute()
  participant Validate as _validate_operator_config
  participant Resolve as _resolve_select_models
  participant Build as _build_generate_argv
  participant RunSF as run_signalforge
  participant Agg as _aggregate_batch_result
  participant Outcome as decide_task_outcome / raise_for_outcome

  DAG->>Op: execute(context)
  Op->>Validate: project_dir, model, select, on_flagged
  Validate-->>Op: ok or AirflowConfigError

  alt --select batch
    Op->>Resolve: project_dir, select expr
    Resolve-->>Op: sorted tuple of unique_ids
    loop per unique_id
      Op->>Build: model=unique_id, write, flags
      Build-->>Op: argv
      Op->>RunSF: argv
      RunSF-->>Op: SignalForgeRunResult
    end
    Op->>Agg: sequence of results
    Agg-->>Op: aggregated SignalForgeRunResult
  else single model
    Op->>Build: model, write, flags
    Build-->>Op: argv
    Op->>RunSF: argv
    RunSF-->>Op: SignalForgeRunResult
  end

  Op->>Outcome: result, on_flagged
  Outcome-->>Op: AirflowSkipException / AirflowFailException / XCom dict
  Op-->>DAG: XCom payload or raises exception
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Possibly related PRs

  • wjduenow/SignalForge#239: Directly related — this PR replaces the skeleton SignalForgeGenerateOperator stub in src/signalforge/airflow/operators.py that was introduced by the packaging/skeleton work in #239.
  • wjduenow/SignalForge#240: Tightly coupled — this PR's execute() and argv tests depend on the SignalForgeRunResult, decide_task_outcome, and raise_for_outcome XCom contract introduced in #240.

Suggested labels

airflow

🐇 A hop, a skip, a generate run,
The operator's born — lazy, zero imports done!
Per-model loops with XCom to spare,
on_flagged="fail" keeps pipelines fair.
From stub to shim, the skeleton's gone —
SignalForge drifts on, and on, and on! 🌟

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 71.05% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: introduction of the Airflow SignalForgeGenerateOperator as part of issue #232, directly matching the substantial operator implementation and integration work across the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands and usage tips.

wjduenow added 8 commits June 15, 2026 22:04
…fig-validation helpers (#232 US-001)

Add two pure, airflow-free module-level helpers to
signalforge.airflow.operators:

- _build_generate_argv(...) maps operator params to a 'signalforge
  generate' CLI argv list: positional <model> XOR --select <expr>,
  always --project-dir + --format json, write=False->--dry-run /
  write=True->--write (DEC-003), plus optional --no-grade / --as-of /
  --cache-scope / --profiles-dir.
- _validate_operator_config(...) raises AirflowConfigError (DEC-009) on
  empty project_dir, model/select mutex violations, leading-dash
  argv-injection, and on_flagged outside {fail,skip,succeed}.

No 'from airflow' import (confinement scan stays green); no I/O. The
NotImplementedError stub class is unchanged (US-003 owns the real
operator). New ungated test file covers every branch.
…_result helpers (#232 US-002)

Add two airflow-free pure helpers to signalforge.airflow.operators:

- _resolve_select_models(project_dir, select) -> tuple[str, ...]: loads the
  dbt manifest and resolves a --select expression to sorted unique_ids,
  mapping ManifestError / SelectorParseError / zero-match to AirflowConfigError
  (carrying the source .remediation, chaining via from exc) (DEC-001/006).
- _aggregate_batch_result(results) -> SignalForgeRunResult: rolls up per-model
  batch results into one aggregate (max exit_code, summed counts, unioned
  model_unique_ids, mean of non-None grades, summed non-None durations, None
  sidecar paths, empty stdout/stderr) (DEC-008).

Extend tests/airflow/test_operators_helpers.py (ungated) covering every
branch: selector resolution against the dbt_project_multi fixture (valid,
multi-atom union, parse-error, zero-match, missing/invalid project_dir) and
batch aggregation (max-exit, count sums, mean-grade with/without None,
duration sums, single-result, cleared sidecars, empty-input ValueError).
 US-003)

Replace the #230 stub with the real generate operator via deferred class
construction: a module-level PEP 562 __getattr__ resolves the
SignalForgeGenerateOperator name through a find_spec-guarded factory.

- Airflow present: the cached factory builds the real BaseOperator subclass
  (base obtained via the one shim make_base_operator(); the from-airflow import
  stays confined there, out of module scope).
- Airflow absent: the name resolves WITHOUT importing airflow (find_spec does
  not execute the module) to an airflow-free placeholder whose construction
  raises ModuleNotFoundError. Attribute access stays airflow-free so the
  no-eager-import / import-confinement gates keep passing; only construction of
  the real operator needs airflow.

execute() dispatches single-model (build argv -> run_signalforge ->
decide_task_outcome -> raise_for_outcome -> to_xcom) vs --select batch (resolve
selector to model ids, loop once per model, force --cache-scope project for a
>=2-model batch when unset, aggregate, return {"models", "aggregate"}).
__init__ + execute both run _validate_operator_config (DAG-parse fail-fast +
rendered-value dash guard). template_fields per DEC-005.

Update the skeleton test to assert airflow-free access + construction-raises
under no-airflow; add gated tests/airflow/test_operators.py (pytest.mark.airflow
+ in-test importorskip) covering the decision table, argv shape, batch loop +
forced project cache scope, and construction-time validation.

Default suite green (3920 passed, 123 deselected); operators.py 100% covered
(gated factory + real class body pragma'd); no-eager-import + import-confinement
gates pass.
…ender-template test

Add examples/airflow/signalforge_generate_operator_dag.py — a single-task
drift monitor (dag_id signalforge_generate_operator, task_id drift_monitor)
built with SignalForgeGenerateOperator directly. write=False (dry-run default),
project_dir/select/on_flagged sourced from env-then-Variable with safe parse-time
fallbacks. Demonstrates template_fields: select={{ params.select }} and
as_of={{ ds }}.

Extend tests/airflow/test_dag_parse.py (gated, airflow marker + per-test
importorskip): parametrize _load_example_dag by dag_id; add a parse test for the
new DAG (import_errors == {}, task_ids == {drift_monitor}) and a
render_template_fields test asserting select/as_of render the injected context.
Existing PythonOperator DAG test untouched.
…rtion)

Add a SignalForgeGenerateOperator section to docs/airflow-ops.md covering the
param->CLI-flag table (with template_fields), write=False=--dry-run (DEC-003),
on_flagged branches (DEC-008), the invocation concurrency caveat (DEC-004),
cost/time guardrails via committed signalforge.yml (DEC-002), --select batch
per-model XCom + aggregate task-state (DEC-001/008/010), the concurrent
project_dir sidecar caveat, and a minimal usage example. Refine the --select
batch section to distinguish the raw seam (last-writer-wins) from the operator
(loops per model). Update the status note + caveats to reflect the operator has
landed. mkdocs nav already lists airflow-ops.md (no nav change).
…lass, manifest-id guard comment, 1-model batch test

Review findings fixed:
- functools.cache replaces manual global+TOCTOU caching of the deferred operator class
- comment: manifest-resolved unique_ids are trusted (no leading-dash guard needed)
- new gated test: --select resolving to exactly 1 model (no cache-scope force, batch XCom shape)
Certified: 22 passed against airflow 2.10.4.
@wjduenow wjduenow changed the title #232: Airflow SignalForgeGenerateOperator (plan) #232: Airflow SignalForgeGenerateOperator Jun 16, 2026
@wjduenow
wjduenow marked this pull request as ready for review June 16, 2026 05:58
@wjduenow

Copy link
Copy Markdown
Owner Author

Implementation landed (Ralph run)

All 7 stories from the plan shipped on this branch:

  • US-001/US-002 — airflow-free pure helpers (_build_generate_argv, _validate_operator_config, _resolve_select_models, _aggregate_batch_result), 100% covered ungated.
  • US-003 — real SignalForgeGenerateOperator.execute(). Deferred class construction (module __getattr__ + find_spec("airflow") branch + airflow-free placeholder) keeps import signalforge.airflow airflow-free while the operator subclasses BaseOperator when airflow is present. No from airflow in operators.py.
  • US-004 — operator-based example DAG (examples/airflow/signalforge_generate_operator_dag.py) + DagBag-parse + template-render tests.
  • US-005docs/airflow-ops.md operator section + .claude/rules/airflow-integration.md.
  • US-006 (Quality Gate) — 4 review lenses (correctness/security/tests/conventions); fixed 1 medium (1-model --select test gap) + 2 low (functools.cache for the class cache; manifest-id trust comment).
  • US-007 — patterns/memory captured.

Validation

  • Default suite: 3920 passed, ruff + ruff format + pyright clean; operators.py 100% covered.
  • Gated certification against real Airflow 2.10.4 (.venv-airflow): 22 passed, 1 skipped (the skip is the live-warehouse e2e needing SF_RUN_BQ).

Decisions worth a look (vetoable)

  • DEC-008 batch task-state = aggregate max-exit-code (mirrors the CLI _run_batch); a mixed tier-2/tier-3 batch maps to FAIL_RETRYABLE.
  • DEC-002 config_overrides deferred — grade cost ceilings come from the committed signalforge.yml (no --config flag exists yet).
  • US-003 deviation — implemented as a find_spec access-time branch rather than pure factory-on-access, to keep the no-eager-import gate green; documented in code + the rule file.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 4

🧹 Nitpick comments (1)
docs/airflow-ops.md (1)

8-16: ⚡ Quick win

Keep docs/airflow-ops.md focused on current behavior, not shipped-status narration.

The “has landed / roadmap / epic-issue” phrasing reads like release-history narrative. Move that historical framing to CHANGELOG.md / plans/super/* / .claude/rules/*, and keep this page strictly operational.

As per coding guidelines: “Do not re-narrate shipped work; those three places own the historical record.”

Also applies to: 408-411

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/airflow-ops.md` around lines 8 - 16, Remove the release-history
narrative from the operations documentation in docs/airflow-ops.md.
Specifically, eliminate the phrases "has landed (epic `#228`, issue `#232`)",
"remains on the roadmap", and other shipped-status descriptions that narrate
development history rather than document current behavior. Instead, restructure
the content to focus purely on what the operators (SignalForgeGenerateOperator
and related helpers) do operationally: describe their contracts, parameters, and
usage patterns. Move any historical context about what has shipped, what is
planned, or which features landed in which version to CHANGELOG.md,
plans/super/*, or .claude/rules/* where that narrative belongs. Apply this same
refactoring to lines 408-411 where similar roadmap/shipped-status language
appears.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/airflow-ops.md`:
- Line 199: The internal anchor links in the markdown file are using
automatically generated slugs that don't resolve reliably, breaking in-page
navigation. Fix the broken anchor references at lines 199, 255, 269, and 340 by
adding explicit, stable HTML id attributes (using markdown syntax like
`{`#custom-id`}` or HTML `<a id="custom-id"></a>`) to the target section headers,
then update the corresponding link fragments to reference these explicit IDs
instead of relying on auto-generated slugs. This ensures that intra-document
navigation works consistently regardless of header text variations.

In `@src/signalforge/airflow/operators.py`:
- Around line 445-464: In the batch loop where run_signalforge is called for
each model_id, the results being collected may contain per-model sidecar path
fields (diff_sidecar_path, grade_sidecar_path) that are misleading because in
write mode all models write to the same fixed project paths rather than stable
per-model locations. Review the SignalForgeRunResult type and the results being
appended to the results list, then remove or exclude the per-model sidecar path
fields from the returned data structure to avoid implying that each model has
its own stable artifact at those paths. The sidecar paths should not be returned
as per-model data when they are actually shared/overwritten across models.
- Around line 148-152: The validation logic in the mutex check at lines 148-152
only verifies that model and select are not None, but does not reject empty
strings or whitespace-only values, allowing blank values to bypass validation
and be passed downstream. Update the condition to also check that the values are
not empty or whitespace by using appropriate string validation methods (such as
checking if the string is falsy after stripping whitespace) alongside the None
checks, and raise AirflowConfigError for blank/whitespace values. Apply the same
validation fix to the related validation code at lines 154-163 to ensure
consistent rejection of blank model or select values across all validation
points.

In `@tests/airflow/test_skeleton.py`:
- Around line 83-100: The assertion in
test_generate_operator_access_is_airflow_free_and_construction_requires_airflow
that checks sys.modules is not deterministic because it inspects the global
state without first normalizing prior airflow imports. Before the assertion that
validates no airflow modules are loaded, remove any pre-existing airflow-related
modules from sys.modules to ensure a clean slate for the test. This way the
assertion will only reflect the behavior of the lazy import mechanism itself,
not prior test pollution or plugin side effects.

---

Nitpick comments:
In `@docs/airflow-ops.md`:
- Around line 8-16: Remove the release-history narrative from the operations
documentation in docs/airflow-ops.md. Specifically, eliminate the phrases "has
landed (epic `#228`, issue `#232`)", "remains on the roadmap", and other
shipped-status descriptions that narrate development history rather than
document current behavior. Instead, restructure the content to focus purely on
what the operators (SignalForgeGenerateOperator and related helpers) do
operationally: describe their contracts, parameters, and usage patterns. Move
any historical context about what has shipped, what is planned, or which
features landed in which version to CHANGELOG.md, plans/super/*, or
.claude/rules/* where that narrative belongs. Apply this same refactoring to
lines 408-411 where similar roadmap/shipped-status language appears.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2854db83-6690-46da-9773-f4d9e3bcb13e

📥 Commits

Reviewing files that changed from the base of the PR and between 235954c and c7bf7b0.

📒 Files selected for processing (9)
  • .claude/rules/airflow-integration.md
  • docs/airflow-ops.md
  • examples/airflow/signalforge_generate_operator_dag.py
  • plans/super/232-generate-operator.md
  • src/signalforge/airflow/operators.py
  • tests/airflow/test_dag_parse.py
  • tests/airflow/test_operators.py
  • tests/airflow/test_operators_helpers.py
  • tests/airflow/test_skeleton.py

Comment thread docs/airflow-ops.md Outdated
Comment thread src/signalforge/airflow/operators.py
Comment thread src/signalforge/airflow/operators.py
Comment thread tests/airflow/test_skeleton.py

Copilot AI 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.

Pull request overview

This PR implements the first real Apache Airflow operator integration for SignalForge by replacing the prior skeleton SignalForgeGenerateOperator with a lazily-resolved BaseOperator subclass that can run signalforge generate for a single model or a --select batch, while preserving the “no eager Airflow import” contract.

Changes:

  • Implemented SignalForgeGenerateOperator with airflow-free helper functions and a gated Airflow-dependent execute() path (including batch looping + aggregation).
  • Added ungated helper unit tests plus gated operator execution and DAG-parse/render tests.
  • Added an operator-based example DAG and updated Airflow ops documentation and integration rules to reflect the new recommended surface.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/signalforge/airflow/operators.py Adds airflow-free argv/config/select/aggregation helpers plus lazy operator class construction and execution wiring.
tests/airflow/test_skeleton.py Updates the skeleton test to validate airflow-free attribute access and Airflow-required construction behavior.
tests/airflow/test_operators.py New gated tests covering operator execute() behavior, argv construction, outcome translation, and batch semantics.
tests/airflow/test_operators_helpers.py New ungated tests covering pure helper functions for argv building, validation, selector resolution, and batch aggregation.
tests/airflow/test_dag_parse.py Extends gated DAG-parse tests to include the operator-based example and template rendering assertions.
examples/airflow/signalforge_generate_operator_dag.py Adds a single-task operator-first drift monitor example DAG.
docs/airflow-ops.md Documents the new operator, parameter→flag mappings, dry-run semantics, and batch/XCom behavior.
.claude/rules/airflow-integration.md Updates integration rules to include the shipped operator patterns and constraints.
plans/super/232-generate-operator.md Adds the #232 plan document describing decisions and implementation structure.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/signalforge/airflow/operators.py
Comment thread src/signalforge/airflow/operators.py
Comment thread docs/airflow-ops.md Outdated
Comment thread plans/super/232-generate-operator.md
- _validate_operator_config: reject blank/non-str model/select before the mutex
  (model="" no longer bypasses 'exactly one' and emits an empty positional)
- _build_generate_argv: treat empty cache_scope as absent (no '--cache-scope ""')
- batch XCom: null per-model sidecar paths (unstable under shared O_TRUNC sidecar)
- test_skeleton: snapshot sys.modules before/after for a deterministic no-eager assertion
- docs: de-link fragile intra-page anchors (duplicate headings); clarify flagged-exits-0
  only under grade.fail_on_below_threshold=false
+ ungated tests for the new branches; certified 22 passed vs airflow 2.10.4
@wjduenow

Copy link
Copy Markdown
Owner Author

PR Review Summary

All 8 review threads addressed in 73dbf73 (+ PR body updated). Every item fixed; no deferrals.

Fixed (7 items)

File Issue Reviewer(s)
operators.py _validate_operator_config Blank/non-str model/select bypassed the mutex (model="" emitted an empty positional) — now rejected before the mutex with a "non-empty string" error CodeRabbit + Copilot (triangulated)
operators.py _build_generate_argv cache_scope="" emitted --cache-scope "" (argparse choices would reject) — empty now treated as absent Copilot
operators.py batch XCom Per-model diff/grade_sidecar_path were unstable (shared O_TRUNC sidecar, last-writer-wins) — nulled in per-model XCom via _without_sidecar_paths; counts/grades stay per-model CodeRabbit (Major)
test_skeleton.py No-eager-import assertion was order-dependent — now snapshots sys.modules before/after (asserts access does not add airflow) CodeRabbit
docs/airflow-ops.md Broken intra-page anchors (duplicate section headings de-dupe the slugs) — de-linked to bold section refs CodeRabbit
docs/airflow-ops.md "flagged exits 0" only holds under default grade.fail_on_below_threshold=false — clarified the =true → exit 2 → FAIL_NO_RETRY path Copilot

New ungated tests cover the blank/non-str/empty-cache_scope branches and _without_sidecar_paths; the gated batch test now asserts the nulled per-model paths. Re-certified 22 passed vs Airflow 2.10.4.

Documented (1 item)

File Issue Disposition
plans/super/232-...md:6 Plan phase devolved vs PR body "detailing" The plan metadata (devolved) is authoritative and correct — the PR body was the draft-stage snapshot from /super-plan publish. Fixed by updating the PR body to the implemented state.

@wjduenow
wjduenow merged commit bc41661 into dev Jun 16, 2026
7 checks passed
@wjduenow
wjduenow deleted the feature/232-generate-operator branch June 16, 2026 15:11
wjduenow added a commit that referenced this pull request Jun 16, 2026
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