Skip to content

Commit 194454d

Browse files
Phase B/1: floor to >=2.7.1, capability block deleted, resolution re-proved
THE FLOOR IS 2.7.1, NOT 2.7.0. Checked PyPI at execution time as instructed: the first check showed 2.7.0 (uploaded 17:48:38Z) and no 2.7.1. The clean install minutes later resolved 2.7.1 — the fast-follow landed at 18:24:03Z, between the check and the install. Re-verified, and floored on the later one per the rule: the fleet's floor round happens once. 2.7.0 is what this app cannot START without — configure_geo, the operator panel, per-vendor policy and the rate ceiling are all called unconditionally. 2.7.1 is additive (rel="describedby" discovery relations on both document lanes plus Link headers, a text/plain Accept ramp, and a source digest that makes representation parity provable). Nothing in this app needed changing for it; the suite proves that. Moved in EVERY encoding, found by grepping the number rather than by memory — which turned up a third, staler one nobody had touched: requirements.txt >=2.6.1 -> >=2.7.1 (all four extras) run.py LLMS_PKG_FLOOR (2,6,1) -> (2,7,1), message rewritten ci.yml the install pin AND both version asserts, which were still on >=2.3.4 from the template THE CAPABILITY BLOCK IS GONE. That was its design promise, not a convenience — a guard kept past the condition it guards is a guard nobody can reason about. Collapsed to a plain import, and every guarded call site with it: - run.py's try/except + LLMS_HAS_27 + _llms_config_27() kwarg filter; - the three vendor_policy / effective_policies fallbacks in the showcase exec modules, which existed only to keep the app booting on the old floor; - tests/conftest.py's requires_dimll_27 skipif and the pytestmark in six test modules. That marker could no longer fire — the floor makes it unreachable — and a skipif that can never trigger is a test suite quietly lying about its own coverage. THE RE-PROOF. Phase 1 mirrored the boilerplate's resolved venv because the sandbox had no network, and said so. This is the real thing: fresh venv on Python 3.12 (CI's primary, not phase 1's 3.11), full resolve from PyPI. It pulled genuinely newer transitives than the mirror — DMC 2.8.0, plotly 6.9.0, pandas 3.0.5, numpy 2.5.2, gunicorn 26.1.0 — and the suite is green on all of it. 597 passed / 1 skipped (flask) 594 passed / 4 skipped (fastapi, ASGI extras installed as ci.yml does) audit_links: 0 broken internal, 0 external, 0 anchors Also verified, since the soak's attestation was on a local file: PyPI's 2.7.0 wheel has a different sha256 from the one soaked (e9c69d18… vs 05180075…) but the SAME size, and extracting it shows all 25 source files byte-identical. A rebuild at upload time, not different code.
1 parent cb49d0f commit 194454d

14 files changed

Lines changed: 98 additions & 198 deletions

‎.github/workflows/ci.yml‎

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ jobs:
142142
if [ "${{ matrix.backend }}" != "flask" ]; then
143143
pip install "dash[${{ matrix.backend }}]" httpx
144144
# The backend extra from PyPI, same floor as requirements.txt.
145-
pip install "dash-improve-my-llms[${{ matrix.backend }}]>=2.3.4"
145+
pip install "dash-improve-my-llms[${{ matrix.backend }}]>=2.7.1"
146146
fi
147147
pip install pytest pytest-cov
148148
# An explicit matrix pin overrides requirements.txt, to prove the
@@ -162,9 +162,11 @@ jobs:
162162
163163
# 4.4 floor: 4.3.0's FastAPI backend 500s on every non-root URL.
164164
assert parts(dash.__version__)[:2] >= (4, 4), dash.__version__
165-
# 2.3.4 is the network standard: below it `resolve_site_title` does
166-
# not exist and this site's published identity degrades to app.title.
167-
assert parts(pkg.__version__) >= (2, 3, 4), pkg.__version__
165+
# 2.7.1 is this app's floor. 2.7.0 is what it cannot START without
166+
# (configure_geo, the panel, per-vendor policy and the rate ceiling
167+
# are all called unconditionally); 2.7.1 is the standards
168+
# fast-follow the fleet floors on so the round happens once.
169+
assert parts(pkg.__version__) >= (2, 7, 1), pkg.__version__
168170
# 21.x carried two request-smuggling CVEs (CVE-2024-6827,
169171
# CVE-2024-1135). markdown2dash's spurious <22 pin must not win.
170172
assert parts(gunicorn.__version__)[:2] >= (23, 0), gunicorn.__version__
@@ -234,7 +236,7 @@ jobs:
234236
235237
v = version('dash-improve-my-llms')
236238
print('dash-improve-my-llms', v)
237-
assert parts(v) >= (2, 3, 4), f'expected >=2.3.4 (resolve_site_title), image has {v}'
239+
assert parts(v) >= (2, 7, 1), f'expected >=2.7.1 (geo guardrail, panel, vendor policy, discovery relations), image has {v}'
238240
239241
# markdown2dash installs with --no-deps to dodge its gunicorn<22
240242
# pin; this assert is what proves the dodge kept working. 21.x

‎docs/crawler_view/crawler_view.py‎

Lines changed: 26 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -31,36 +31,25 @@
3131

3232

3333
def _ua_options():
34-
"""Real UA tokens grouped by class, from whichever API this build has.
34+
"""Real UA tokens grouped by class, straight from the vendor registry.
3535
36-
`vendors` is a 2.7.0 module and this repo still floors on 2.6.1 (see
37-
run.py's LLMS_HAS_27 block), so the richer registry is used when it is
38-
there and the 2.6.x token lists when it is not. This runs at LAYOUT time,
39-
which is why it cannot simply assume the newer API: an ImportError here
40-
takes down the whole app at boot, not just this showcase.
36+
Runs at LAYOUT time, so it depends on `vendors` existing — which the
37+
>=2.7.0 floor in requirements.txt guarantees. It carried a pre-2.7.0
38+
fallback while that floor was still 2.6.1; the floor moved on
39+
2026-08-23 and the fallback went with it.
4140
"""
41+
from dash_improve_my_llms.vendors import VENDORS
42+
4243
groups = {"training": [], "search": [], "traditional": []}
43-
try:
44-
from dash_improve_my_llms.vendors import VENDORS
45-
46-
for vendor in VENDORS:
47-
# Not every vendor publishes a robots token: `anthropic-legacy` is
48-
# a UA-only identity (anthropic-ai, claude-web) with an empty
49-
# robots_tokens tuple, so fall back to what the middleware
50-
# matches on.
51-
token = (vendor.robots_tokens or vendor.ua_tokens or (vendor.key,))[0]
52-
groups.setdefault(vendor.cls, []).append(
53-
{"value": f"{token}/1.0",
54-
"label": f"{vendor.display} — {vendor.operator}"}
55-
)
56-
except ImportError: # pre-2.7.0: the flat token lists, no operator names
57-
from dash_improve_my_llms import bot_detection
58-
59-
for cls, tokens in (("training", bot_detection.AI_TRAINING_BOTS),
60-
("search", bot_detection.AI_SEARCH_BOTS),
61-
("traditional", bot_detection.TRADITIONAL_BOTS)):
62-
for token in tokens:
63-
groups[cls].append({"value": f"{token}/1.0", "label": token})
44+
for vendor in VENDORS:
45+
# Not every vendor publishes a robots token: `anthropic-legacy` is a
46+
# UA-only identity (anthropic-ai, claude-web) with an empty
47+
# robots_tokens tuple, so fall back to what the middleware matches on.
48+
token = (vendor.robots_tokens or vendor.ua_tokens or (vendor.key,))[0]
49+
groups.setdefault(vendor.cls, []).append(
50+
{"value": f"{token}/1.0",
51+
"label": f"{vendor.display} — {vendor.operator}"}
52+
)
6453

6554
data = [{"group": "A human's browser",
6655
"items": [{"value": BROWSER_UA, "label": "Chrome 120 (a person)"}]}]
@@ -161,22 +150,20 @@ def _show(path, user_agent):
161150
is_bot = is_any_bot(user_agent)
162151
bot_class = get_bot_type(user_agent) if is_bot else "human"
163152

164-
# Same 2.6.1 degrade as _ua_options: without the registry there is no
165-
# vendor identity and no per-vendor fold, so the class defaults stand in.
166-
vendor, policy = None, "allow"
167-
try:
168-
from dash_improve_my_llms.bot_detection import get_bot_vendor
169-
from dash_improve_my_llms.vendors import VENDORS, effective_policies
153+
from dash_improve_my_llms.bot_detection import get_bot_vendor
154+
from dash_improve_my_llms.vendors import VENDORS, effective_policies
170155

171-
vendor = next((v for v in VENDORS if v.key == get_bot_vendor(user_agent)), None)
172-
if vendor is not None:
156+
vendor = next((v for v in VENDORS if v.key == get_bot_vendor(user_agent)), None)
157+
policy = "allow"
158+
if vendor is not None:
159+
try:
173160
policy = effective_policies(
174161
getattr(dash.get_app(), "_robots_config", None)
175162
)[vendor.key]
176-
except ImportError:
177-
policy = "block" if bot_class == "training" else "allow"
178-
except Exception:
179-
policy = "allow"
163+
except Exception:
164+
# The fold reads a live config object; a showcase must degrade
165+
# rather than break the page it is embedded in.
166+
policy = "allow"
180167

181168
verdict = _verdict_card(is_bot, vendor, bot_class, policy)
182169

‎docs/policy_panel/policy_panel.py‎

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,14 +123,13 @@ def _summary_cards(denied):
123123
import dash
124124
from dash_improve_my_llms import __version__ as pkg_version
125125

126-
try:
127-
# `vendors` is 2.7.0; this repo still floors on 2.6.1 (run.py's
128-
# LLMS_HAS_27 block), so the fold is optional and its absence shows
129-
# as zero rather than an error toast.
130-
from dash_improve_my_llms.vendors import effective_policies
126+
from dash_improve_my_llms.vendors import effective_policies
131127

128+
try:
132129
policies = effective_policies(getattr(dash.get_app(), "_robots_config", None))
133130
except Exception:
131+
# The fold reads a live config object; a public showcase degrades to
132+
# zeroes rather than throwing an error toast at a reader.
134133
policies = {}
135134
blocked = sum(1 for value in policies.values() if value == "block")
136135
metered = sum(1 for value in policies.values() if value == "meter")

‎docs/robots_sandbox/robots_sandbox.py‎

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,9 @@
2121

2222

2323
def _vendor_rows():
24-
"""(key, display, operator, class) per vendor — [] before 2.7.0.
25-
26-
Runs at LAYOUT time, so an ImportError here would take down the app at
27-
boot rather than degrading this one showcase. See run.py's LLMS_HAS_27
28-
block: this repo still floors on 2.6.1 on purpose.
29-
"""
30-
try:
31-
from dash_improve_my_llms.vendors import VENDORS
32-
except ImportError:
33-
return []
24+
"""(key, display, operator, class) for every vendor in the registry."""
25+
from dash_improve_my_llms.vendors import VENDORS
26+
3427
return [(v.key, v.display, v.operator, v.cls) for v in VENDORS]
3528

3629

@@ -123,23 +116,18 @@ def _render(training, search, traditional, docs, delay, vendor, action):
123116
from dash_improve_my_llms.robots_generator import generate_robots_txt
124117

125118
# THROWAWAY. Never assigned to the app — see this module's docstring.
126-
kwargs = dict(
119+
from dash_improve_my_llms.vendors import effective_policies
120+
121+
config = RobotsConfig(
127122
block_ai_training=bool(training),
128123
allow_ai_search=bool(search),
129124
allow_traditional=bool(traditional),
125+
block_ai_training_docs=bool(docs),
130126
crawl_delay=int(delay) if delay else None,
127+
vendor_policy={vendor: action} if vendor else None,
131128
)
132-
try:
133-
from dash_improve_my_llms.vendors import effective_policies
134-
135-
kwargs["block_ai_training_docs"] = bool(docs)
136-
kwargs["vendor_policy"] = {vendor: action} if vendor else None
137-
except ImportError: # pre-2.7.0: neither keyword exists
138-
effective_policies = None
139-
140-
config = RobotsConfig(**kwargs)
141129
robots = generate_robots_txt(sitemap_url=SITEMAP, base_url=BASE_URL, config=config)
142-
policies = effective_policies(config) if effective_policies else {}
130+
policies = effective_policies(config)
143131

144132
robots_panel = dmc.Paper(
145133
dmc.Code(robots, block=True,

‎requirements.txt‎

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -117,15 +117,32 @@ python-dotenv>=1.0.0
117117
# (the invented daily dates are gone — Google discards a sitemap of lies
118118
# wholesale), JSON-LD publisher.logo, and the llms.txt viewer banner
119119
# de-dup. Floor, not pin: the fleet upgrades through this line.
120-
# 2.6.1 floor: the universal prerender ships VISIBLE to non-JS consumers
121-
# (below it the block carries a literal `hidden` attribute and every
122-
# visibility-respecting reader sees only "Loading..." — the outside-audit
123-
# finding of 2026-08-22). run.py's boot floor and a test in
124-
# tests/test_pages.py encode the same number — grep it, don't move one.
125-
dash-improve-my-llms[flask]>=2.6.1
126-
# dash-improve-my-llms[fastapi]>=2.6.1 # Dash 4.4+ FastAPI backend
127-
# dash-improve-my-llms[quart]>=2.6.1 # Dash 4.4+ Quart backend
128-
# dash-improve-my-llms[all]>=2.6.1 # all three
120+
# 2.7.1 floor (2026-08-23). TWO releases matter here and the floor names the
121+
# later one deliberately — the fleet's floor round happens once.
122+
#
123+
# 2.7.0, the agent toll gate, is what this app CANNOT START without: it calls
124+
# `configure_geo`, `LLMSConfig(panel=)`, `RobotsConfig(vendor_policy=)` and
125+
# the rate ceiling unconditionally, so anything lower is an ImportError at
126+
# boot rather than a degraded feature. It also carries the two defects this
127+
# repo's own soak found and gated the tag on (BUGS-2.7.0.md #1 and #2): a
128+
# `deny_countries` callable returning a nested object used to 500 EVERY
129+
# request on EVERY surface, and a per-vendor block on a traditional crawler
130+
# was enforced but never published in robots.txt. Both are reachable from the
131+
# control board this site ships, which is why they were blocking.
132+
#
133+
# 2.7.1 is the standards fast-follow, published 36 minutes after 2.7.0 and
134+
# additive throughout: `rel="describedby"` discovery relations on both
135+
# document lanes plus HTTP `Link` headers, a `text/plain` Accept ramp for
136+
# retrieval stacks that reject `text/markdown`, and a `llms-source-digest`
137+
# that makes representation parity across the three lanes provable rather
138+
# than plausible.
139+
#
140+
# 2.6.1 remains the previous rung and its reason is still live: below it the
141+
# universal prerender ships VISIBLE to non-JS consumers.
142+
dash-improve-my-llms[flask]>=2.7.1
143+
# dash-improve-my-llms[fastapi]>=2.7.1 # Dash 4.4+ FastAPI backend
144+
# dash-improve-my-llms[quart]>=2.7.1 # Dash 4.4+ Quart backend
145+
# dash-improve-my-llms[all]>=2.7.1 # all three
129146

130147
# Clerk authentication (dash-clerk-auth, vendored — not on PyPI).
131148
#

‎run.py‎

Lines changed: 24 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ def _version(text: str) -> tuple:
7979
# `configure_seo` is deliberately imported AFTER this floor fires (see the
8080
# floors block) so a stale environment gets the floor's diagnosis instead of
8181
# a bare ImportError.
82-
LLMS_PKG_FLOOR = (2, 6, 1)
82+
LLMS_PKG_FLOOR = (2, 7, 1)
8383

8484
# THE FORK POINT — claim this app's network identity before any
8585
# hub-facing module imports. Every module that names this app
@@ -174,6 +174,10 @@ def _dependency_floor(message: str, fatal: bool) -> None:
174174
_dependency_floor(
175175
f"dash-improve-my-llms {LLMS_PKG_VERSION} is below the "
176176
f"{'.'.join(str(n) for n in LLMS_PKG_FLOOR)} floor in requirements.txt. "
177+
"Below 2.7.0 this app does not start at all: it calls configure_geo, "
178+
"LLMSConfig(panel=), RobotsConfig(vendor_policy=) and the rate "
179+
"ceiling unconditionally, and the control board writes through the "
180+
"callable seams all four expose. "
177181
"Below 2.6.1 the universal prerender ships `hidden`, so every "
178182
"visibility-respecting consumer (text extractors, arguably crawler "
179183
"content-weighting) reads 'Loading...' instead of the page's prose. "
@@ -203,56 +207,18 @@ def configure_seo(**_kwargs) -> None:
203207
"package) — crawler identity tags and root icons not emitted."
204208
)
205209

206-
# ----------------------------------------------------------------------------
207-
# The 2.7.0 surface: the geo guardrail, the operator panel, per-vendor policy
208-
# and the rate ceiling. Same post-floor pattern as configure_seo above, and
209-
# for a sharper reason: requirements.txt still floors at 2.6.1 ON PURPOSE
210-
# (2.7.0 is not on PyPI yet), so this app has to keep booting on the pinned
211-
# floor while the code is written against the newer one. Every 2.7.0 call
212-
# below is guarded by LLMS_HAS_27 rather than by a version comparison —
213-
# capability, not number, so a partial backport or a yanked release cannot
214-
# make the guard lie.
210+
# The 2.7.0 surface: the geo guardrail and the operator panel. Imported after
211+
# the floor check for the same reason configure_seo is — on a package below
212+
# the floor these names do not exist, and the floor's diagnosis above beats a
213+
# bare ImportError.
215214
#
216-
# WHEN 2.7.0 PUBLISHES: move the requirements.txt floor to >=2.7.0, raise
217-
# LLMS_PKG_FLOOR, and this whole block collapses to a plain import. Until
218-
# then the degrade is load-bearing and tests/test_runtime_imports.py keeps
219-
# it honest.
220-
try:
221-
from dash_improve_my_llms import configure_geo, geo as _geo # noqa: E402
222-
223-
LLMS_HAS_27 = True
224-
except ImportError: # pragma: no cover — the pinned 2.6.1 floor
225-
LLMS_HAS_27 = False
226-
_geo = None
227-
228-
def configure_geo(**_kwargs) -> None:
229-
print(
230-
"[llms] WARNING: configure_geo unavailable (pre-2.7.0 package) — "
231-
"the country guardrail is not wired. The control board's geo "
232-
"section will say so rather than pretending to block."
233-
)
234-
235-
236-
def _llms_config_27(**kwargs):
237-
"""`LLMSConfig` with the 2.7.0-only keywords, when they exist.
238-
239-
`panel=` and `rate_limit_per_minute=` are positional-or-keyword arguments
240-
on 2.7.0 and simply absent on 2.6.1, where passing them is a TypeError at
241-
boot rather than a degraded feature. Filtering against the real signature
242-
keeps one call site for both.
243-
"""
244-
import inspect
245-
246-
accepted = inspect.signature(LLMSConfig.__init__).parameters
247-
unsupported = [k for k in kwargs if k not in accepted]
248-
for key in unsupported:
249-
kwargs.pop(key)
250-
if unsupported:
251-
print(
252-
"[llms] WARNING: this dash-improve-my-llms build does not accept "
253-
f"{', '.join(sorted(unsupported))} — feature(s) not wired."
254-
)
255-
return LLMSConfig(**kwargs)
215+
# This was a LLMS_HAS_27 capability block until 2026-08-23, carrying a degrade
216+
# path for every call site because requirements.txt still floored at >=2.6.1
217+
# while 2.7.0 was unpublished. 2.7.0 is on PyPI and the floor moved, so the
218+
# block collapsed to this import — which was its stated design promise, not a
219+
# convenience. A guard kept past the condition it guards is a guard nobody
220+
# can reason about.
221+
from dash_improve_my_llms import configure_geo, geo as _geo # noqa: E402
256222

257223

258224
def _rate_ceiling():
@@ -421,7 +387,7 @@ def _rate_ceiling():
421387
allow_traditional=True, # Allow Googlebot, Bingbot, etc.
422388
crawl_delay=10,
423389
disallowed_paths=[],
424-
**({"vendor_policy": _policy_store.vendor_policy} if LLMS_HAS_27 else {}),
390+
vendor_policy=_policy_store.vendor_policy,
425391
)
426392

427393
# ============================================================================
@@ -755,13 +721,12 @@ async def track_visitor():
755721
policy_url=os.environ.get("GEO_POLICY_URL", ""),
756722
)
757723

758-
if LLMS_HAS_27:
759-
_geo_policy = _geo.effective_policy()
760-
print(
761-
f"[llms] geo guardrail: {len(_geo_policy['deny_countries'])} "
762-
f"country(ies) denied via {_geo_policy['denylist_source']}, unknown="
763-
f"{_geo_policy['unknown']} — store {_policy_store.path()}"
764-
)
724+
_geo_policy = _geo.effective_policy()
725+
print(
726+
f"[llms] geo guardrail: {len(_geo_policy['deny_countries'])} country(ies) "
727+
f"denied via {_geo_policy['denylist_source']}, unknown="
728+
f"{_geo_policy['unknown']} — store {_policy_store.path()}"
729+
)
765730

766731
# Wire up the package: /llms.txt, /<page>/llms.txt, /robots.txt, /sitemap.xml,
767732
# bot-detection middleware, and (on Dash 4.3+) MCP resource registration.
@@ -771,7 +736,7 @@ async def track_visitor():
771736
# DIMLL_PANEL_TOKEN — so an operator can rotate or revoke it live. Register
772737
# it only when the token happens to be set at boot and that promise breaks:
773738
# turning the panel on would cost a redeploy, which is when nobody does it.
774-
add_llms_routes(app, _llms_config_27(
739+
add_llms_routes(app, LLMSConfig(
775740
warn_missing_llms_doc=True,
776741
panel=True,
777742
rate_limit_per_minute=_rate_ceiling(),

‎tests/conftest.py‎

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -87,30 +87,6 @@
8787
STUB_MARKER = "This page contains interactive content that requires JavaScript"
8888

8989

90-
def dimll_has_27() -> bool:
91-
"""Whether the installed package carries the 2.7.0 surface.
92-
93-
A CAPABILITY probe, matching run.py's LLMS_HAS_27: requirements.txt
94-
still floors at >=2.6.1 on purpose, so a clean `pip install -r
95-
requirements.txt` resolves 2.6.1 and every 2.7.0-only test in this suite
96-
has to SKIP rather than fail. A red suite on the pinned floor would train
97-
everyone to ignore it.
98-
"""
99-
try:
100-
import dash_improve_my_llms.vendors # noqa: F401
101-
102-
return True
103-
except ImportError:
104-
return False
105-
106-
107-
requires_dimll_27 = pytest.mark.skipif(
108-
not dimll_has_27(),
109-
reason="needs dash-improve-my-llms >= 2.7.0 (requirements.txt still "
110-
"floors at >=2.6.1 until the tag ships)",
111-
)
112-
113-
11490
def backend() -> str:
11591
"""Whichever backend the app will actually boot on.
11692

‎tests/test_control_board_geo.py‎

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,6 @@
1717

1818
import pytest
1919

20-
from conftest import requires_dimll_27
21-
22-
# Every assertion in this module is about the 2.7.0 surface. On the
23-
# pinned 2.6.1 floor the whole file skips rather than fails.
24-
pytestmark = requires_dimll_27
2520

2621
DENIED = "RU"
2722

0 commit comments

Comments
 (0)