user.email binds across unrelated Django test apps via TIER1R_RECEIVER — 2 live phantoms on master, and #199's own comment says they were gone #246

Closed
opened 2026-09-10 00:47:13 +02:00 by buildagent · 1 comment
Member

Split out of #199, which is now closed on its census half. This is the precision residual, and it is live on master today — measured by the #199/#206/#207 lane at 8a8ea5c.

Measured

tests/auth_tests/test_models.py:281   user.email  ->  tests/select_related_onetoone/models.py:6
tests/auth_tests/test_models.py:293   user.email  ->  tests/select_related_onetoone/models.py:6
resolved_by = 60 = TIER1R_RECEIVER

Two refs in django.contrib.auth's own tests bind email to an unrelated test app's User.email.

Read at source: django.contrib.auth's User gets email from AbstractUser. It is inherited, so there is no email symbol under the User the reference means — and tier 1R, having proven the receiver's type name is User, binds it to the one User in the repository that happened to write email down.

Why this needs its own number

#199's own follow-up comment says these are gone. Written at 1d81180: "zero refs resolve to … User.email anywhere." That was true when written. Since then #69's member arm landed (96d428a), and #203's route-A fix did not remove these two — it removed the relative-specifier class, and this is not one.

So the state of the tracker was "measured and resolved" while the tree says otherwise. Two of #199's original eighteen survive; the other sixteen (the a.id and composite_pk ones) genuinely do not reproduce (target_id IS NULL).

What the existing instruments say

  • precision_gate — cannot see it. It indexes zero corpus repositories, and a phantom scores only against a declared decoy.
  • corpus_ratchet — counts resolutions. These are resolutions; the count went up.
  • The (container, member) ambiguity census — this is exactly the blind spot #199 was about, and #199's fix now discloses the conditions: same_named=14, declared_in=1, undeclared_containers_with_supertypes=11. The census can now say "eleven same-named containers have a supertype mechanism I cannot see through", which is the disclosure. It does not stop the bind.

So the honesty half is shipped and the precision half is open. That split is deliberate and is why this is a separate number.

What must NOT be done

  • Do not widen tier 1R to test the container name rather than the pair. #199 measured that: 12 of 18 phantoms removed, 17 CORRECT binds lost — 15 in rust-analyzer's to_proto.rs where the source is explicit about which crate's type it means and a locality test overrules it. Applied over nine repos, reverted. Proximity is the wrong instrument.
  • Do not raise the resolved count as evidence of anything. Three cuts this year raised it and every extra bind was a phantom.
  • Do not cite precision_gate green. It has twice this week reported 7/7 phantom_count == 0 across changes admitting 34 and 37 wrong corpus binds.

The two directions, from #199, neither attempted

  1. Import evidence — from django.contrib.auth.models import User names the app's own class, and #196's clause is the mechanism. This is the discriminator these binds actually need, and it is the same answer #203 used for the relative half.
  2. Emit the inherited surface — resolve class X(Base) to Base and let member lookup walk the chain. Large; changes the candidate pool everywhere; needs its own bind-for-bind pass.

Direction 1 is the narrower one and is the natural continuation of #203, which spliced module_is_relative and left the absolute-module half explicitly open (that half is #168, currently in flight).

What a fix must prove

  • These two refs stop binding to select_related_onetoone, read at source, and either resolve correctly or resolve to nothing — a phantom replaced by a different phantom is not progress.
  • The 17 correct binds #199 measured as lost do NOT move. That set is the anti-vacuity arm and it is already written down; re-measure it, do not assume the new mechanism spares them.
  • The full corpus bind census, diffed against the prior binary on (path, line, col, kind, occurrence) and split by resolved_by, with every moved row adjudicated at source.
  • A precision_gate decoy for this shape, so the gate stops being blind to it — two same-named containers in unrelated packages where one inherits the member and one declares it.

#199 (closed; this is its precision residual, and its census now discloses the conditions), #69 (whose member arm reaches these), #196 (import evidence), #203 (the relative half, fixed), #168 (the absolute-module half of the stem hazard).

Filed 2026-09-10 against master e425320; measured at 8a8ea5c.

Split out of #199, which is now closed on its census half. This is the precision residual, and it is **live on `master` today** — measured by the #199/#206/#207 lane at `8a8ea5c`. ## Measured ``` tests/auth_tests/test_models.py:281 user.email -> tests/select_related_onetoone/models.py:6 tests/auth_tests/test_models.py:293 user.email -> tests/select_related_onetoone/models.py:6 resolved_by = 60 = TIER1R_RECEIVER ``` Two refs in `django.contrib.auth`'s own tests bind `email` to an **unrelated test app's** `User.email`. Read at source: `django.contrib.auth`'s `User` gets `email` from `AbstractUser`. It is inherited, so there is no `email` symbol under the `User` the reference means — and tier 1R, having proven the receiver's type name is `User`, binds it to the one `User` in the repository that happened to write `email` down. ## Why this needs its own number **#199's own follow-up comment says these are gone.** Written at `1d81180`: *"zero refs resolve to … `User.email` anywhere."* That was true when written. Since then **#69's member arm landed** (`96d428a`), and #203's route-A fix did not remove these two — it removed the *relative-specifier* class, and this is not one. So the state of the tracker was "measured and resolved" while the tree says otherwise. Two of #199's original eighteen survive; the other sixteen (the `a.id` and `composite_pk` ones) genuinely do not reproduce (`target_id IS NULL`). ## What the existing instruments say - `precision_gate` — **cannot see it.** It indexes zero corpus repositories, and a phantom scores only against a *declared* decoy. - `corpus_ratchet` — counts resolutions. These are resolutions; the count went up. - The `(container, member)` ambiguity census — this is exactly the blind spot #199 was about, and #199's fix now **discloses the conditions**: `same_named=14, declared_in=1, undeclared_containers_with_supertypes=11`. The census can now say "eleven same-named containers have a supertype mechanism I cannot see through", which is the disclosure. It does not stop the bind. So the honesty half is shipped and the precision half is open. That split is deliberate and is why this is a separate number. ## What must NOT be done - **Do not widen tier 1R to test the container name rather than the pair.** #199 measured that: **12 of 18 phantoms removed, 17 CORRECT binds lost** — 15 in `rust-analyzer`'s `to_proto.rs` where the source is explicit about which crate's type it means and a locality test overrules it. Applied over nine repos, reverted. Proximity is the wrong instrument. - **Do not raise the resolved count as evidence of anything.** Three cuts this year raised it and every extra bind was a phantom. - **Do not cite `precision_gate` green.** It has twice this week reported 7/7 `phantom_count == 0` across changes admitting 34 and 37 wrong corpus binds. ## The two directions, from #199, neither attempted 1. **Import evidence** — `from django.contrib.auth.models import User` names the app's own class, and #196's clause is the mechanism. This is the discriminator these binds actually need, and it is the same answer #203 used for the relative half. 2. **Emit the inherited surface** — resolve `class X(Base)` to `Base` and let member lookup walk the chain. Large; changes the candidate pool everywhere; needs its own bind-for-bind pass. Direction 1 is the narrower one and is the natural continuation of #203, which spliced `module_is_relative` and left the **absolute-module** half explicitly open (that half is #168, currently in flight). ## What a fix must prove - These two refs stop binding to `select_related_onetoone`, **read at source**, and either resolve correctly or resolve to nothing — a phantom replaced by a different phantom is not progress. - **The 17 correct binds #199 measured as lost do NOT move.** That set is the anti-vacuity arm and it is already written down; re-measure it, do not assume the new mechanism spares them. - The full corpus bind census, diffed against the prior binary on `(path, line, col, kind, occurrence)` and split by `resolved_by`, with every moved row adjudicated at source. - A `precision_gate` decoy for this shape, so the gate stops being blind to it — two same-named containers in unrelated packages where one inherits the member and one declares it. ## Related #199 (closed; this is its precision residual, and its census now discloses the conditions), #69 (whose member arm reaches these), #196 (import evidence), #203 (the relative half, fixed), #168 (the absolute-module half of the stem hazard). Filed 2026-09-10 against `master` `e425320`; measured at `8a8ea5c`.
Author
Member

Released in v0.28.2 through #266. The two real Django user.email occurrences at tests/auth_tests/test_models.py:281:44 and :293:31 no longer bind to the unrelated test application. They remain unresolved because inherited-member traversal is outside this fix. Shadowed import origins reject inconsistent receiver decisions after uniqueness; they cannot manufacture a new unique candidate.

The public installer/archive and both MCP transports were verified. The actual published CLI reproduced all nine final corpus projections: exactly two false bindings removed, every reference population and every other target/rule unchanged, including all 17 required controls and both ContentType controls. Upgrading actual published-v0.28.1 Flask/Django databases matched fresh v0.28.2 indexes without replacing symbol/contribution rows. Native Windows and Linux CI passed. Actual decision-filter, ambiguity, positive-control, migration and precision mutations failed their intended tests, then restored tests passed.

Occurrence-level evidence. Closing the reported false-binding defect.

Published build 0.28.2 (76e8967) was checked through both MCP transports: wrong-target references 0, positive-control references 1 in each. Published Linux CLI SHA-256: 8b82e1099e7f84a84cd0c5d73f2ccbb4173803ba5ec0be0af69bea149eab6036. Release workflow: all 11 jobs passed.

Released in [v0.28.2](https://git.h-dv.de/h-dv/code-index/releases/tag/v0.28.2) through #266. The two real Django user.email occurrences at tests/auth_tests/test_models.py:281:44 and :293:31 no longer bind to the unrelated test application. They remain unresolved because inherited-member traversal is outside this fix. Shadowed import origins reject inconsistent receiver decisions after uniqueness; they cannot manufacture a new unique candidate. The public installer/archive and both MCP transports were verified. The actual published CLI reproduced all nine final corpus projections: exactly two false bindings removed, every reference population and every other target/rule unchanged, including all 17 required controls and both ContentType controls. Upgrading actual published-v0.28.1 Flask/Django databases matched fresh v0.28.2 indexes without replacing symbol/contribution rows. Native Windows and Linux CI passed. Actual decision-filter, ambiguity, positive-control, migration and precision mutations failed their intended tests, then restored tests passed. [Occurrence-level evidence](https://git.h-dv.de/h-dv/code-index/src/tag/v0.28.2/_prdoc/records/issue-246-adjudication.md). Closing the reported false-binding defect. Published build `0.28.2 (76e8967)` was checked through both MCP transports: wrong-target references 0, positive-control references 1 in each. Published Linux CLI SHA-256: `8b82e1099e7f84a84cd0c5d73f2ccbb4173803ba5ec0be0af69bea149eab6036`. [Release workflow](https://git.h-dv.de/h-dv/code-index/actions/runs/760): all 11 jobs passed.
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#246
No description provided.