Found while reviewing #431 (the cgis orphans query, closing #415).
The gap
The query is correct about these classes — nothing constructs, extends or names them — but a reader will not act on any of them, so they dilute the signal. Hand-checking 14 of owner-api's 43 reported orphans:
| category |
count (of 43) |
example |
why it is noise |
| generated code |
16 |
api.dependencies.grpc.services.ConfigServiceStub |
betterproto stubs under api/dependencies/grpc/, header says DO NOT EDIT. Genuinely unused, never hand-deleted. |
| alive by metaclass |
1+ |
domains.rating.schemas.RatingResponse.Config |
a pydantic inner class Config is consumed by the model's metaclass and never named |
| alive by registration |
1+ |
models.chat.ChatAttachment |
SQLModel, table=True — the class is the table definition; importing it is the point |
Usable signal on that repository is roughly 25 of 43. On a repo with a larger generated surface the ratio would be worse.
Why each needs a marker the graph does not have
- Generated: needs an
is_generated notion. The conventions are real and narrow — a DO NOT EDIT / @generated marker in the first few lines, or a configured path glob. This is the highest-value one: 16 of 43.
- Metaclass-consumed nested class:
Config inside a pydantic model is the common case, but "a nested class the enclosing class's metaclass reads" is not visible in the AST at all. A narrower rule — a nested class whose owner is live — would also hide genuinely dead nested classes, so it needs measuring before choosing.
- Registration side-effect:
table=True is a keyword argument in the class definition's bases. Detectable, but it is one framework's convention; the general shape is "a class whose existence is its purpose", which also covers Django models, enum registries, and plugin subclasses.
Suggested order
is_generated from a header marker, and exclude by default with a --include-generated opt-out. Measure the drop on owner-api (expect 43 → ~27) and on the other four repos in the D10 test set.
- Decide the nested-class question with numbers rather than a rule: count how many nested classes the query reports across the five repos, and how many of those are genuinely dead.
table=True only if step 2 leaves it looking common.
The related but distinct limitation — a class named only inside a decorator — is #429, and that one is under-reporting rather than noise.
Found while reviewing #431 (the
cgis orphansquery, closing #415).The gap
The query is correct about these classes — nothing constructs, extends or names them — but a reader will not act on any of them, so they dilute the signal. Hand-checking 14 of owner-api's 43 reported orphans:
api.dependencies.grpc.services.ConfigServiceStubapi/dependencies/grpc/, header saysDO NOT EDIT. Genuinely unused, never hand-deleted.domains.rating.schemas.RatingResponse.Configclass Configis consumed by the model's metaclass and never namedmodels.chat.ChatAttachmentSQLModel, table=True— the class is the table definition; importing it is the pointUsable signal on that repository is roughly 25 of 43. On a repo with a larger generated surface the ratio would be worse.
Why each needs a marker the graph does not have
is_generatednotion. The conventions are real and narrow — aDO NOT EDIT/@generatedmarker in the first few lines, or a configured path glob. This is the highest-value one: 16 of 43.Configinside a pydantic model is the common case, but "a nested class the enclosing class's metaclass reads" is not visible in the AST at all. A narrower rule — a nested class whose owner is live — would also hide genuinely dead nested classes, so it needs measuring before choosing.table=Trueis a keyword argument in the class definition's bases. Detectable, but it is one framework's convention; the general shape is "a class whose existence is its purpose", which also covers Django models, enum registries, and plugin subclasses.Suggested order
is_generatedfrom a header marker, and exclude by default with a--include-generatedopt-out. Measure the drop on owner-api (expect 43 → ~27) and on the other four repos in the D10 test set.table=Trueonly if step 2 leaves it looking common.The related but distinct limitation — a class named only inside a decorator — is #429, and that one is under-reporting rather than noise.