#168 residual: two CORRECT py-django binds lost — views.serve and storage.request.COOKIES #250

Open
opened 2026-09-10 07:39:31 +02:00 by buildagent · 3 comments
Member

Found by a bind-for-bind census of the tier-3 drift, run against the 1d3228e binary
(which predates lanes A–E) and bd1c4e2. py-django moved resolved 108545 → 108401 with
the ref universe byte-identical at 480167 refs, so this is resolution only.

The −144 adjudicates as 150 phantoms removed, 6 correct binds net gained, 2 correct
binds LOST
. That is a large precision win and the trade is clearly right. This issue is
only about the two, so they are not forgotten.

The two losses

1. tests/staticfiles_tests/urls/default.py:5

from django.contrib.staticfiles import views      # line 1
from django.urls import re_path

urlpatterns = [
    re_path("^static/(?P<path>.*)$", views.serve),   # line 5
]

Target was django/contrib/staticfiles/views.py:16 def serve — correct, and the
qualifier views is bound by an import that names exactly that package. It now resolves
to nothing.

2. tests/messages_tests/test_cookie.py:30 — storage.request.COOKIES reaching
django/http/request.py#COOKIES. storage.request is a real HttpRequest, so the bind
was right.

Why they were refused

qual_root_scope_sql scopes the file-stem/file-key anchor arms so a stem anchor cannot
leave the package the qualifier's first segment names. Case 1 has the qualifier naming a
real package whose own views.py is the target, so it looks like it should be ADMITTED
by the rule's own logic rather than refused — worth checking whether the root-reach or
containment clause is too tight here, not whether the gate should exist.

For contrast, the 79 lost type binds in the same repo are unambiguously right to lose:
django/db/models/expressions.py does from django.db.models import fields and its
fields.DateTimeField was binding django/forms/fields.py:532 (the FORMS class) instead
of django/db/models/fields/__init__.py:1600 (the MODEL class). Wrong class, phantom,
and now correctly unresolved.

Reproduction

/usr/local/bin/code-index index --root <corpus>/py-django --db before.db   # 0.27.1 (1d3228e)
target/release/code-index index --root <corpus>/py-django --db after.db    # bd1c4e2

then join refs on (path, start_line, start_col, name) and take rows resolved in
before and unresolved in after with kind NOT IN ('type','method_call'). Seven rows;
five are storage.location/storage.base_location phantoms on a local FileSystemStorage
binding contrib/staticfiles/storage.py, and these two are the correct ones.

Recorded in tier3-baseline.json's bless reason so the number is not silently carried.

Found by a bind-for-bind census of the tier-3 drift, run against the `1d3228e` binary (which predates lanes A–E) and `bd1c4e2`. py-django moved `resolved` 108545 → 108401 with the ref universe **byte-identical** at 480167 refs, so this is resolution only. The −144 adjudicates as **150 phantoms removed, 6 correct binds net gained, 2 correct binds LOST**. That is a large precision win and the trade is clearly right. This issue is only about the two, so they are not forgotten. ## The two losses **1. `tests/staticfiles_tests/urls/default.py:5`** ```python from django.contrib.staticfiles import views # line 1 from django.urls import re_path urlpatterns = [ re_path("^static/(?P<path>.*)$", views.serve), # line 5 ] ``` Target was `django/contrib/staticfiles/views.py:16 def serve` — correct, and the qualifier `views` is bound by an import that names exactly that package. It now resolves to nothing. **2. `tests/messages_tests/test_cookie.py:30`** — `storage.request.COOKIES` reaching `django/http/request.py#COOKIES`. `storage.request` is a real `HttpRequest`, so the bind was right. ## Why they were refused `qual_root_scope_sql` scopes the file-stem/file-key anchor arms so a stem anchor cannot leave the package the qualifier's first segment names. Case 1 has the qualifier naming a real package whose own `views.py` is the target, so it looks like it should be ADMITTED by the rule's own logic rather than refused — worth checking whether the root-reach or containment clause is too tight here, not whether the gate should exist. For contrast, the 79 lost `type` binds in the same repo are unambiguously right to lose: `django/db/models/expressions.py` does `from django.db.models import fields` and its `fields.DateTimeField` was binding `django/forms/fields.py:532` (the FORMS class) instead of `django/db/models/fields/__init__.py:1600` (the MODEL class). Wrong class, phantom, and now correctly unresolved. ## Reproduction ``` /usr/local/bin/code-index index --root <corpus>/py-django --db before.db # 0.27.1 (1d3228e) target/release/code-index index --root <corpus>/py-django --db after.db # bd1c4e2 ``` then join `refs` on `(path, start_line, start_col, name)` and take rows resolved in `before` and unresolved in `after` with `kind NOT IN ('type','method_call')`. Seven rows; five are `storage.location`/`storage.base_location` phantoms on a local `FileSystemStorage` binding `contrib/staticfiles/storage.py`, and these two are the correct ones. Recorded in `tier3-baseline.json`'s bless reason so the number is not silently carried.
Author
Member

Loss 1 and all of #251 are the same missing distinction, in opposite directions

Worth linking these before either is worked, because a fix aimed at one
alone will very likely move the other — and they pull opposite ways.

this issue, loss 1 #251
import form from django.contrib.staticfiles import views import inspect
what the form says the qualifier is the module django.contrib.staticfiles.views the top-level module inspect
the anchor taken none — refused django/utils/inspect.py
verdict correct bind LOST (gate too tight) phantom GAINED (anchor too loose)

Both sites are qualifier.name(...) where the qualifier was bound by an
import. In neither case is the current rule consulting what the import
form actually says about the module's location
— it is matching on
file stem and then applying a containment gate as a separate,
after-the-fact scope test.

Python states the location precisely in the syntax:

  • import X — absolute, top-level (PEP 328). It can never mean a
    sibling file. #251's 13 phantoms are all anchors on non-top-level
    files.
  • from A.B import X — X is exactly A.B.X when X is a module.
    Loss 1's target is django/contrib/staticfiles/views.py, i.e.
    precisely the module the import names — which is why the issue text
    above says it "looks like it should be ADMITTED by the rule's own
    logic".

So the general mechanism is one thing rather than two: resolve the
qualifier through the import that bound it into a full module path, then
require the anchor file to BE that module
— not to merely share its
stem, and not to pass a separate containment test afterwards.

That admits loss 1 (the module path matches exactly) and refuses all 13
of #251 (django.utils.inspect ≠ inspect), with the same clause. A
patch that only loosens the gate here risks re-admitting #251's
phantoms; a patch that only tightens #251 risks losing more binds of
this shape.

Loss 2 is NOT this shape

storage.request.COOKIES is a receiver chain — storage.request is an
HttpRequest instance, not a module — so it is tier-1R/receiver
territory and no import-form rule reaches it. It should be tracked
separately rather than folded in, or it will be the case that quietly
fails to be fixed while the issue is closed.

The constraint on doing it

Language-scoped, and measured bind-for-bind before anything is blessed.
tier1q_root_scope.rs:19 already records an unscoped variant of a
neighbouring clause at −1244 on rust-analyzer, which is what an
import-semantics rule applied outside Python would look like. Details in
the analysis on #251.

## Loss 1 and all of #251 are the same missing distinction, in opposite directions Worth linking these before either is worked, because a fix aimed at one alone will very likely move the other — and they pull opposite ways. | | this issue, loss 1 | #251 | |---|---|---| | import form | `from django.contrib.staticfiles import views` | `import inspect` | | what the form says the qualifier is | the module `django.contrib.staticfiles.views` | the **top-level** module `inspect` | | the anchor taken | none — refused | `django/utils/inspect.py` | | verdict | **correct bind LOST** (gate too tight) | **phantom GAINED** (anchor too loose) | Both sites are `qualifier.name(...)` where the qualifier was bound by an import. In neither case is the current rule consulting **what the import form actually says about the module's location** — it is matching on file stem and then applying a containment gate as a separate, after-the-fact scope test. Python states the location precisely in the syntax: - `import X` — absolute, **top-level** (PEP 328). It can never mean a sibling file. #251's 13 phantoms are all anchors on non-top-level files. - `from A.B import X` — `X` is exactly `A.B.X` when `X` is a module. Loss 1's target *is* `django/contrib/staticfiles/views.py`, i.e. precisely the module the import names — which is why the issue text above says it "looks like it should be ADMITTED by the rule's own logic". So the general mechanism is one thing rather than two: **resolve the qualifier through the import that bound it into a full module path, then require the anchor file to BE that module** — not to merely share its stem, and not to pass a separate containment test afterwards. That admits loss 1 (the module path matches exactly) and refuses all 13 of #251 (`django.utils.inspect` ≠ `inspect`), with the same clause. A patch that only loosens the gate here risks re-admitting #251's phantoms; a patch that only tightens #251 risks losing more binds of this shape. ## Loss 2 is NOT this shape `storage.request.COOKIES` is a receiver chain — `storage.request` is an `HttpRequest` instance, not a module — so it is tier-1R/receiver territory and no import-form rule reaches it. It should be tracked separately rather than folded in, or it will be the case that quietly fails to be fixed while the issue is closed. ## The constraint on doing it Language-scoped, and measured bind-for-bind before anything is blessed. `tier1q_root_scope.rs:19` already records an unscoped variant of a neighbouring clause at **−1244 on rust-analyzer**, which is what an import-semantics rule applied outside Python would look like. Details in the analysis on #251.
Author
Member

Verified against the actual published v0.28.1 CLI (340a75a) and pinned Django corpus:

  • tests/staticfiles_tests/urls/default.py:5:44 now resolves views.serve to django/contrib/staticfiles/views.py:16 serve.
  • tests/messages_tests/test_cookie.py:30:21 remains an unresolved write through storage.request.COOKIES.

The remaining case needs evidence across an untyped helper argument, inherited storage/request factories, constructor argument-to-field assignment, and the fallback storage list path. The current receiver-origin rule does not establish those flows. A basename or unique-field fallback would recreate the false-binding class this work removed. Keeping this issue open for that remaining implementation; PR #266 addresses #246 and #263 separately.

Verified against the actual published [v0.28.1](https://git.h-dv.de/h-dv/code-index/releases/tag/v0.28.1) CLI (`340a75a`) and pinned Django corpus: - `tests/staticfiles_tests/urls/default.py:5:44` now resolves `views.serve` to `django/contrib/staticfiles/views.py:16 serve`. - `tests/messages_tests/test_cookie.py:30:21` remains an unresolved write through `storage.request.COOKIES`. The remaining case needs evidence across an untyped helper argument, inherited storage/request factories, constructor argument-to-field assignment, and the fallback storage list path. The current receiver-origin rule does not establish those flows. A basename or unique-field fallback would recreate the false-binding class this work removed. Keeping this issue open for that remaining implementation; PR #266 addresses #246 and #263 separately.
Author
Member

Rechecked both reported occurrences with the actual published v0.28.2 CLI (76e8967) on the pinned Django corpus. tests/staticfiles_tests/urls/default.py:5:44 still resolves views.serve to django/contrib/staticfiles/views.py:16. tests/messages_tests/test_cookie.py:30:21 (storage.request.COOKIES) remains unresolved.

This issue stays open. The remaining chain requires caller-argument flow, inherited factory results, constructor-to-field flow, and the fallback caller's backend collection path. Existing local constructor/annotation facts do not prove that chain. No global same-name field fallback was added to manufacture a target. The v0.28.2 notes disclose this remaining gap.

Rechecked both reported occurrences with the actual published v0.28.2 CLI (`76e8967`) on the pinned Django corpus. `tests/staticfiles_tests/urls/default.py:5:44` still resolves `views.serve` to `django/contrib/staticfiles/views.py:16`. `tests/messages_tests/test_cookie.py:30:21` (`storage.request.COOKIES`) remains unresolved. This issue stays open. The remaining chain requires caller-argument flow, inherited factory results, constructor-to-field flow, and the fallback caller's backend collection path. Existing local constructor/annotation facts do not prove that chain. No global same-name field fallback was added to manufacture a target. The [v0.28.2 notes](https://git.h-dv.de/h-dv/code-index/releases/tag/v0.28.2) disclose this remaining gap.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
h-dv/code-index#250
No description provided.