Skip to content

Commit 7941831

Browse files
committed
fix(bundles): floor lfx pin at the minor line's .dev0 so nightlies resolve (forward-port)
The first 1.11.0.dev0 nightly failed its "Test Langflow Main CLI" step: the fork bump's sync_bundle_lfx_pin.py re-synced every bundle floor to lfx>=1.11.0, and PEP 440 sorts the nightly's 1.11.0.dev0 BELOW 1.11.0, so the workspace-built bundles (whose metadata shadows the satisfiable PyPI lfx-arxiv 0.1.1 during `uv pip install dist/*.whl`) reject the branch's own lfx while langflow-base pins it exactly — unresolvable. Floor at lfx>=X.Y.0.dev0,<(X+1).0.0 instead: X.Y.0.dev0 is the lowest version PEP 440 admits in the minor line, so every devN / rcN / final satisfies the floor while older lines and the next major stay excluded. This closes the NIGHTLY.md activation-gate hole structurally — future minor forks re-sync to a floor their own nightlies already satisfy. - sync_bundle_lfx_pin.py: lfx_floor_spec emits the .dev0 floor - port_bundle.py: mirrored _current_lfx_floor kept in step - bundle pyprojects restamped via the script (arxiv/docling/duckduckgo/ibm) - test_bundle_lfx_pin.py expectations updated (20/20 passing) - NIGHTLY.md gate section annotated with the post-activation fix uv.lock is unaffected (workspace lfx is recorded as an editable source with no specifier — which is also why uv sync/lock passed in the same job). The release.yml RC floor-relax sed still matches the new form; now redundant but harmless. No bundle version bump needed: published 0.1.1 floors >=1.10.0.rc0, satisfiable by the whole 1.11 line. Forward-port of ee659ca from release-1.11.0. Main is on the 1.10.0 line, so the bundle floors here restamp to lfx>=1.10.0.dev0,<2.0.0 via the same sync script; the next minor fork's make patch now produces a floor its own X.Y.0.devN nightlies satisfy.
1 parent 13a937c commit 7941831

8 files changed

Lines changed: 51 additions & 27 deletions

File tree

scripts/ci/sync_bundle_lfx_pin.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,18 @@
88
no upper bound, which silently permitted resolving against the now-dead 0.5.x
99
line -- and neither pip nor uv flags the cross-line jump.
1010
11-
Pin form: ``lfx>=X.Y.0,<(X+1).0.0`` -- floored at the current minor line,
12-
capped below the next lfx major. The cap is a coarse install-time guard
13-
against an untested lfx major; fine-grained BUNDLE_API compatibility is still
14-
enforced at load time by each ``extension.json``'s ``lfx.compat`` list against
15-
the running lfx's ``BUNDLE_API_VERSION`` (see
11+
Pin form: ``lfx>=X.Y.0.dev0,<(X+1).0.0`` -- floored at the very first
12+
pre-release of the current minor line, capped below the next lfx major. The
13+
``.dev0`` floor (not ``X.Y.0``) is load-bearing: nightlies off a release
14+
branch are canonical ``X.Y.0.devN`` pre-releases, and PEP 440 sorts those
15+
BELOW ``X.Y.0`` -- a plain ``>=X.Y.0`` floor makes the branch's own nightly
16+
``lfx`` unresolvable against its own bundles (langflow-base pins
17+
``lfx==X.Y.0.devN`` exactly, so the resolver cannot back off). ``X.Y.0.dev0``
18+
is the lowest version PEP 440 admits in the line, so every devN / rcN / final
19+
satisfies it while older minor lines stay excluded. The cap is a coarse
20+
install-time guard against an untested lfx major; fine-grained BUNDLE_API
21+
compatibility is still enforced at load time by each ``extension.json``'s
22+
``lfx.compat`` list against the running lfx's ``BUNDLE_API_VERSION`` (see
1623
``src/lfx/src/lfx/extension/manifest.py``).
1724
1825
Idempotent: re-running with the same version is a no-op (so it is safe to call
@@ -53,8 +60,10 @@
5360
def lfx_floor_spec(version: str) -> str:
5461
"""Return the bundle ``lfx`` dependency spec for a Langflow/LFX version.
5562
56-
``"1.10.0"`` -> ``"lfx>=1.10.0,<2.0.0"`` (floor at the minor line start,
57-
cap below the next lfx major). A leading ``v`` is tolerated.
63+
``"1.11.0"`` -> ``"lfx>=1.11.0.dev0,<2.0.0"`` (floor at the minor line's
64+
first pre-release so the branch's own ``X.Y.0.devN`` nightlies resolve --
65+
see the module docstring; cap below the next lfx major). A leading ``v``
66+
is tolerated.
5867
5968
NOTE: this floor format is duplicated in ``scripts/migrate/port_bundle.py``
6069
(``_current_lfx_floor``) so each script stays standalone; keep them in step.
@@ -64,7 +73,7 @@ def lfx_floor_spec(version: str) -> str:
6473
msg = f"Unparseable version {version!r}; expected X.Y.Z"
6574
raise ValueError(msg)
6675
major, minor = int(match.group(1)), int(match.group(2))
67-
return f"lfx>={major}.{minor}.0,<{major + 1}.0.0"
76+
return f"lfx>={major}.{minor}.0.dev0,<{major + 1}.0.0"
6877

6978

7079
def rewrite_lfx_dep(content: str, floor_spec: str) -> str:

scripts/migrate/port_bundle.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,19 +69,21 @@ def _current_lfx_floor() -> str:
6969
"""Return the ``lfx`` dependency floor for a freshly-ported bundle.
7070
7171
Reads the workspace lfx version from ``src/lfx/pyproject.toml`` and pins
72-
``lfx>=X.Y.0,<(X+1).0.0`` -- floored at the current major.minor line,
73-
capped below the next lfx major. Mirrors ``lfx_floor_spec`` in
74-
``scripts/ci/sync_bundle_lfx_pin.py`` (each script is kept standalone, so
75-
keep the two in step); that script re-syncs every existing bundle on
76-
``make patch``.
72+
``lfx>=X.Y.0.dev0,<(X+1).0.0`` -- floored at the current major.minor
73+
line's first pre-release (the branch's own canonical ``X.Y.0.devN``
74+
nightlies sort below a plain ``X.Y.0`` under PEP 440, so they must be
75+
admitted by the floor), capped below the next lfx major. Mirrors
76+
``lfx_floor_spec`` in ``scripts/ci/sync_bundle_lfx_pin.py`` (each script
77+
is kept standalone, so keep the two in step); that script re-syncs every
78+
existing bundle on ``make patch``.
7779
"""
7880
lfx_pyproject = (REPO_ROOT / "src" / "lfx" / "pyproject.toml").read_text(encoding="utf-8")
7981
match = re.search(r'^version = "(\d+)\.(\d+)\.\d+', lfx_pyproject, re.MULTILINE)
8082
if not match:
8183
msg = "Could not read lfx version from src/lfx/pyproject.toml"
8284
raise ValueError(msg)
8385
major, minor = int(match.group(1)), int(match.group(2))
84-
return f"lfx>={major}.{minor}.0,<{major + 1}.0.0"
86+
return f"lfx>={major}.{minor}.0.dev0,<{major + 1}.0.0"
8587

8688

8789
# ---------------------------------------------------------------------------

src/backend/tests/unit/test_bundle_lfx_pin.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,18 @@ def _load_module():
3636

3737

3838
class TestLfxFloorSpec:
39+
# The .dev0 floor is load-bearing: nightlies are canonical X.Y.0.devN
40+
# pre-releases, which PEP 440 sorts BELOW X.Y.0, so a plain >=X.Y.0
41+
# floor makes the branch's own nightly lfx unresolvable.
3942
@pytest.mark.parametrize(
4043
("version", "expected"),
4144
[
42-
("1.10.0", "lfx>=1.10.0,<2.0.0"),
43-
("1.10.3", "lfx>=1.10.0,<2.0.0"), # patch within a minor -> same floor
44-
("1.11.0", "lfx>=1.11.0,<2.0.0"),
45-
("2.0.0", "lfx>=2.0.0,<3.0.0"),
46-
("v1.10.0", "lfx>=1.10.0,<2.0.0"), # leading v tolerated
47-
("10.4.2", "lfx>=10.4.0,<11.0.0"), # multi-digit major
45+
("1.10.0", "lfx>=1.10.0.dev0,<2.0.0"),
46+
("1.10.3", "lfx>=1.10.0.dev0,<2.0.0"), # patch within a minor -> same floor
47+
("1.11.0", "lfx>=1.11.0.dev0,<2.0.0"),
48+
("2.0.0", "lfx>=2.0.0.dev0,<3.0.0"),
49+
("v1.10.0", "lfx>=1.10.0.dev0,<2.0.0"), # leading v tolerated
50+
("10.4.2", "lfx>=10.4.0.dev0,<11.0.0"), # multi-digit major
4851
],
4952
)
5053
def test_floor(self, version, expected):
@@ -62,7 +65,7 @@ def test_rejects_unparseable(self, bad):
6265

6366

6467
class TestRewriteLfxDep:
65-
FLOOR = "lfx>=1.10.0,<2.0.0"
68+
FLOOR = "lfx>=1.10.0.dev0,<2.0.0"
6669

6770
def test_rewrites_bare_floor(self):
6871
assert mod.rewrite_lfx_dep(' "lfx>=0.5.0",', self.FLOOR) == f' "{self.FLOOR}",'
@@ -121,11 +124,11 @@ def _make_bundle(self, bundles_dir: Path, name: str, lfx_line: str) -> Path:
121124
def test_sync_updates_and_reports(self, tmp_path):
122125
bundles = tmp_path / "bundles"
123126
self._make_bundle(bundles, "arxiv", "lfx>=0.5.0")
124-
self._make_bundle(bundles, "ibm", "lfx>=1.10.0,<2.0.0") # already correct
127+
self._make_bundle(bundles, "ibm", "lfx>=1.10.0.dev0,<2.0.0") # already correct
125128

126129
results = dict(mod.sync_bundles("1.10.0", bundles))
127130
assert results == {"arxiv": True, "ibm": False} # arxiv changed, ibm no-op
128-
assert '"lfx>=1.10.0,<2.0.0"' in (bundles / "arxiv" / "pyproject.toml").read_text()
131+
assert '"lfx>=1.10.0.dev0,<2.0.0"' in (bundles / "arxiv" / "pyproject.toml").read_text()
129132

130133
def test_sync_idempotent(self, tmp_path):
131134
bundles = tmp_path / "bundles"

src/bundles/NIGHTLY.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,16 @@ Why (2) is not optional: a bundle pins `lfx>=1.10.0,<2.0.0`, and PEP 440 sorts `
8181
daily from **main's** workflow definition, so merging this before the gate would break the live
8282
nightly on the next run.
8383

84+
> **Post-activation fix (2026-06):** condition (2) as stated was still fragile — the `release-1.11.0`
85+
> fork's `make patch v=1.11.0` re-synced every bundle floor to `lfx>=1.11.0`
86+
> (`scripts/ci/sync_bundle_lfx_pin.py`), which sorts **above** that same branch's `1.11.0.devN`
87+
> nightlies and reintroduced exactly this conflict on the very first `1.11.0.dev0` nightly (the
88+
> workspace-built bundle's metadata shadows the satisfiable PyPI `0.1.1` in the
89+
> `uv pip install dist/*.whl` test step). The synced floor format is now
90+
> `lfx>=X.Y.0.dev0,<(X+1).0.0``X.Y.0.dev0` is the lowest version PEP 440 admits in the minor
91+
> line, so every `devN` / `rcN` / final satisfies it while older lines stay excluded, and the gate
92+
> can no longer regress on future minor forks.
93+
8494
## A1 vs A2 + remaining follow-ups (decide before activating)
8595

8696
This PR implements the **A1** publish behavior: the separate `langflow-nightly` / `langflow-base-nightly`

src/bundles/arxiv/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ keywords = ["langflow", "lfx", "extension", "bundle", "arxiv", "search"]
1515
# but we list it here as a direct runtime dep so the bundle keeps building
1616
# even if lfx drops it later.
1717
dependencies = [
18-
"lfx>=1.10.0,<2.0.0",
18+
"lfx>=1.10.0.dev0,<2.0.0",
1919
"defusedxml>=0.7.1,<1.0.0",
2020
]
2121

src/bundles/docling/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ keywords = ["langflow", "lfx", "extension", "bundle", "docling", "documents"]
1414
# base dependency because the bundle exchanges DoclingDocument objects even when
1515
# conversion happens remotely.
1616
dependencies = [
17-
"lfx>=1.10.0,<2.0.0",
17+
"lfx>=1.10.0.dev0,<2.0.0",
1818
"httpx>=0.28.1,<1.0.0",
1919
"docling-core>=2.36.1,<3.0.0",
2020
]

src/bundles/duckduckgo/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ keywords = ["langflow", "lfx", "extension", "bundle", "duckduckgo", "search"]
1818
# "lfx": {"compat": [...]} contract. langchain-community uses the same
1919
# range the lfx tree does to keep co-installation lockstep.
2020
dependencies = [
21-
"lfx>=1.10.0,<2.0.0",
21+
"lfx>=1.10.0.dev0,<2.0.0",
2222
"langchain-community>=0.4.1,<1.0.0",
2323
"ddgs>=9.0.0",
2424
]

src/bundles/ibm/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ keywords = ["langflow", "lfx", "extension", "bundle", "ibm", "db2", "watsonx", "
2626
# 3.10-compatible build elsewhere. Kept in lockstep with langflow-base.
2727
# * ``langchain-community`` provides the helpers DB2VS leans on.
2828
dependencies = [
29-
"lfx>=1.10.0,<2.0.0",
29+
"lfx>=1.10.0.dev0,<2.0.0",
3030
"langchain-community>=0.4.1,<1.0.0",
3131
"ibm-db>=3.2.9,<4.0.0; sys_platform != 'linux' or platform_machine != 'aarch64'",
3232
"ibm-watsonx-ai>=1.3.1,<2.0.0",

0 commit comments

Comments
 (0)