# Python Anti-Slop SKILL.md

> Source: <https://gist.github.com/pipethedev/5707c47edd0d6994347adef72c533de9>
> Published: 2026-09-10 10:50:25+00:00

| name | anti-slop-python | 
|---|---|
| description | Simplify Python code by removing defensive over-engineering, unnecessary abstractions, generic dictionaries, excessive runtime checks, wrapper helpers, and AI-generated architectural noise. | 

Apply these rules whenever modifying Python code.

The goal is simple, explicit, typed, idiomatic Python that is easy to trace and does not defend against impossible internal states.

The default philosophy is:

**Validate untrusted data at the boundary. Use precise types and straightforward Python everywhere else.**

Prefer boring code over clever abstractions.

Search aggressively for:

```
Any
dict[str, Any]
Mapping[str, Any]
list[Any]
object
```

inside normal application logic.

If the shape is known, define it.

Bad:

``` php
def get_domain(data: dict[str, Any]) -> str:
    value = data.get("domain")

    if not isinstance(value, str):
        return ""

    return value
```

Prefer:

```
@dataclass
class DomainEvent:
    domain: str
```

Then:

```
event.domain
```

Or use the project's existing model system:

```
class DomainEvent(BaseModel):
    domain: str
```

Do not carry untyped dictionaries deep into the application.

Be suspicious of functions such as:

```
as_string
to_string
safe_string
string_value
to_int
as_int
safe_int
to_bool
to_dict
as_dict
ensure_dict
normalize_value
```

Bad:

``` php
def to_string(value: Any) -> str:
    if value is None:
        return ""

    if isinstance(value, str):
        return value

    if isinstance(value, int):
        return str(value)

    if isinstance(value, ObjectId):
        return str(value)

    return repr(value)
```

Ask:

What is this value actually supposed to be?

If it is a string:

``` php
def normalize_domain(domain: str) -> str:
    return domain.strip().lower()
```

Do not make every function capable of accepting arbitrary Python values.

Bad:

``` php
def normalize_domain(value: Any) -> str:
    if isinstance(value, str):
        return value.strip().lower()

    if isinstance(value, int):
        return str(value).strip().lower()

    return ""
```

A domain name should not randomly be an integer.

Prefer:

``` php
def normalize_domain(domain: str) -> str:
    return domain.strip().lower()
```

Types should describe valid application states.

Do not broaden inputs solely to make code more "defensive."

Bad:

``` php
def as_project(value: Any) -> Project:
    if not isinstance(value, dict):
        return {}

    return cast(Project, value)
```

This does not validate `Project`.

Either validate at the boundary using the project's real validation mechanism, or trust the value at a known integration point.

Do not write several runtime checks and still finish with `cast()`.

Do not treat every `cast()` as inherently bad.

Bad cleanup:

```
if (
    isinstance(error, Exception)
    and hasattr(error, "code")
    and isinstance(error.code, int)
    and error.code == DUPLICATE_KEY_ERROR_CODE
):
    ...
```

when this is enough at a known driver boundary:

```
return cast(Any, error).code == DUPLICATE_KEY_ERROR_CODE
```

Better still, use the driver's actual exception type if available:

```
except DuplicateKeyError:
    ...
```

Do not turn one simple, understood assumption into five branches merely to avoid a cast.

Do not manually inspect generic exceptions when the library exposes a concrete exception.

Bad:

```
except Exception as exc:
    if getattr(exc, "code", None) == 11000:
        ...
```

Prefer:

```
except DuplicateKeyError:
    ...
```

Use exception APIs provided by the dependency.

Do not reinvent error classification.

Be suspicious of:

```
try:
    ...
except Exception:
    return None
```

or:

```
try:
    ...
except Exception:
    pass
```

or:

```
try:
    ...
except Exception as exc:
    logger.error(exc)
    return {}
```

Catch exceptions you can actually handle.

Do not silently convert unexpected programming errors into empty values.

Avoid:

```
try:
    ...
except:
    pass
```

except at extremely deliberate process-level boundaries.

Bare `except` also catches system-exiting exceptions.

Use specific exception types.

Bad:

```
try:
    return await service.run()
except Exception:
    raise
```

Delete the `try/except`.

Likewise:

```
try:
    ...
except Exception as exc:
    raise exc
```

is usually worse than letting the exception propagate naturally.

Bad:

```
try:
    await operation()
except Exception:
    return None
```

If failure is acceptable, make that business rule explicit.

If it is not acceptable, let the error propagate.

Silent failure is not robustness.

Bad:

```
try:
    return repository.get_project(project_id)
except Exception:
    logger.exception("Failed to get project")
    raise
```

if an outer handler also logs the same error.

Prefer returning/raising errors through internal layers and logging once at the responsible boundary.

Avoid duplicate stack traces.

Search for suspicious patterns like:

```
return ""
return {}
return []
return None

value or ""
value or {}
value or []

data.get("field", "")
data.get("field", {})
```

when the fallback hides an invalid state.

Bad:

```
project_id = data.get("project_id", "")
```

if `project_id` is required.

Prefer validation at the boundary and then:

```
project_id = data.project_id
```

Do not hide missing required values.

Bad:

```
name = project.get("name")
region = project.get("region")
config = project.get("config", {})
```

when the schema guarantees those keys.

If it is a typed dictionary:

```
class ProjectData(TypedDict):
    name: str
    region: str
    config: ProjectConfig
```

prefer:

```
project["name"]
project["region"]
project["config"]
```

Or better, use a model/dataclass where appropriate.

Use `.get()` when absence is actually valid.

Bad:

```
domain = (
    data.get("project", {})
    .get("config", {})
    .get("domain", {})
    .get("name")
)
```

This usually hides malformed input.

Prefer modeling the structure properly.

```
data.project.config.domain.name
```

or validated dictionary access.

Do not turn invalid nested structures into `None` silently.

Be suspicious of:

```
dict[str, Any]
Mapping[str, Any]
MutableMapping[str, Any]
```

moving between:

```
handler
→ service
→ manager
→ repository
→ processor
```

If the schema is known, define a model.

Possible tools include:

- dataclasses
- TypedDict
- Pydantic models
- attrs
- domain classes

Use whichever the project already uses.

Do not introduce another modeling framework unnecessarily.

Good:

```
class QueuePayload(TypedDict):
    event: str
    data: dict[str, Any]
```

can be appropriate at a JSON-shaped boundary.

But do not turn the entire domain model into nested TypedDicts if actual objects would make business logic clearer.

Use the simplest representation that fits the project.

Dataclasses are useful when a plain object represents structured internal data.

Good:

```
@dataclass(frozen=True)
class DomainMapEvent:
    project_id: str
    domain: str
```

Avoid adding:

```
__post_init__
classmethod factories
builder methods
conversion methods
validation methods
```

unless they enforce meaningful invariants.

A dataclass should not become a mini-framework.

Pydantic is excellent at boundaries.

It does not need to become the base representation for every internal object.

Use it where validation/parsing is valuable:

- HTTP requests
- environment/config
- external payloads
- queue events
- API responses

Inside trusted application code, plain dataclasses or typed objects may be simpler.

Follow the codebase's existing style.

Bad:

```
request = ProjectRequest.model_validate(payload)

...

service.create_project(request)

...

if not request.project_id:
    raise ValueError(...)

...

if not isinstance(request.project_id, str):
    ...
```

If the boundary model already validated it, trust it.

Do not revalidate the same object at every layer.

Bad:

```
if not isinstance(project.id, str):
    return None
```

when:

```
@dataclass
class Project:
    id: str
```

already guarantees it.

Trust internal types.

If the type is inaccurate, fix the type.

Be suspicious of:

```
if hasattr(value, "id"):
    ...
```

or:

```
domain = getattr(document, "domain", None)
```

when the object has a known type.

Prefer:

```
document.domain
```

Use `getattr` for truly dynamic APIs, not as general defensive programming.

Bad:

```
project_id = getattr(project, "id", "")
```

if `project.id` is required.

Prefer:

```
project.id
```

If the object may genuinely be absent:

```
if project is None:
    raise ProjectNotFound(...)
```

Then continue normally.

Be suspicious of:

```
getattr
setattr
hasattr
vars
__dict__
inspect
dir
```

inside ordinary business logic.

Python is dynamic, but that does not mean application code should discover its own shape at runtime.

Use explicit attributes and types.

If a feature relies heavily on:

```
inspect.signature
inspect.getmembers
inspect.isclass
```

ask whether the code is building infrastructure/framework behavior or simply avoiding explicit APIs.

Reflection is appropriate in frameworks/tooling.

It is suspicious in normal domain logic.

Bad:

``` php
def serialize_value(value: Any) -> str:
    if isinstance(value, str):
        return value
    if isinstance(value, int):
        return str(value)
    if isinstance(value, ObjectId):
        return str(value)
    if isinstance(value, datetime):
        return value.isoformat()
    return repr(value)
```

unless arbitrary-value serialization is genuinely the feature.

If you know the field type, serialize that type directly.

Be suspicious of:

```
domain_id_from
project_id_from
extract_id
extract_name
resolve_field
safe_field
object_id_from
string_from
```

Bad:

``` php
def domain_id_from(document: dict[str, Any] | None) -> str | None:
    if document is None:
        return None

    domain = document.get("domain")

    if not isinstance(domain, ObjectId):
        return None

    return str(domain)
```

If the document contract is known:

```
@dataclass
class DNSDocument:
    domain: ObjectId
```

then:

```
str(document.domain)
```

Fix typing rather than introducing another helper.

Be suspicious of functions that:

- have one caller
- are one to three lines
- only access a property
- only call `.strip()`
- only call `.lower()`
- only perform `isinstance`
- only return a fallback
- only forward parameters
- only rename another function

Bad:

``` php
def get_project_id(project: Project) -> str:
    return project.id
```

Prefer:

```
project.id
```

Helpers should represent real concepts.

Do not split simple logic into:

```
parser.py
normalizer.py
validator.py
converter.py
mapper.py
resolver.py
helper.py
processor.py
manager.py
```

for a tiny feature.

Keep related code together when it improves readability.

Separation of concerns does not mean separation of every statement.

Be suspicious of:

```
Controller
→ Service
→ Manager
→ Processor
→ Handler
→ Repository
→ DAO
```

when most layers simply forward parameters.

Python does not need enterprise ceremony.

Collapse layers that add no logic.

Bad:

``` php
class ProjectManager:
    def get_project(self, project_id: str) -> Project:
        return self.project_service.get_project(project_id)
```

and then:

``` php
class ProjectService:
    def get_project(self, project_id: str) -> Project:
        return self.repository.get_project(project_id)
```

If a layer adds no policy, transformation, caching, orchestration, or meaningful abstraction, remove it.

Be suspicious of:

```
class BaseService:
    ...

class BaseRepository:
    ...

class AbstractManager:
    ...
```

when subclasses share little meaningful behavior.

Do not create inheritance hierarchies just to centralize two utility methods.

Prefer composition or direct code.

Bad:

```
class MongoProjectRepository(BaseRepository, LoggingMixin, RetryMixin):
    ...
```

when dependencies/functions can be explicit.

Multiple inheritance and mixin stacks make behavior hard to trace.

Use them only when they genuinely simplify the architecture.

Be suspicious of:

```
LoggingMixin
ValidationMixin
SerializationMixin
RetryMixin
TimestampMixin
ErrorHandlingMixin
```

for ordinary application classes.

Mixins often hide dependencies and control flow.

Prefer explicit calls or composition.

Do not create:

```
class ProjectRepository(Protocol):
    ...

class AbstractProjectRepository(ABC):
    ...
```

when there is one concrete implementation and no real abstraction need.

Protocols/interfaces are useful for narrow consumer contracts and interchangeable implementations.

Do not add them because "good architecture requires interfaces."

Bad:

``` python
class ProjectGetter(Protocol):
    def get_project(...):
        ...
```

created solely because one test needs a mock.

Python's testing ecosystem already supports dependency substitution easily.

Use protocols when they express a meaningful contract.

Bad:

``` php
class RepositoryFactory:
    def create(self, type_: str) -> Repository:
        ...
```

when the application always uses one repository.

Prefer direct construction.

Factories should solve actual runtime selection or complex setup.

Bad:

```
deployment = (
    DeploymentBuilder()
    .with_project_id(project_id)
    .with_region(region)
    .with_port(port)
    .build()
)
```

Prefer:

```
deployment = Deployment(
    project_id=project_id,
    region=region,
    port=port,
)
```

Python already has excellent object construction syntax.

Do not emulate Java builders unnecessarily.

Be suspicious of:

```
Project.from_dict(...)
Project.from_payload(...)
Project.from_model(...)
Project.from_entity(...)
Project.from_record(...)
```

when the transformations are trivial or duplicate one another.

Use alternative constructors only when they express genuinely different construction logic.

Audit:

```
to_dict
from_dict
to_model
from_model
to_dto
from_dto
to_entity
from_entity
to_schema
from_schema
```

If two representations are nearly identical, question why both exist.

Do not maintain fleets of copy-field transformations without a real boundary distinction.

Be suspicious of:

```
Project
ProjectDTO
ProjectData
ProjectPayload
ProjectRequest
ProjectResponse
ProjectModel
ProjectEntity
ProjectRecord
```

with almost the same fields.

Separate models where API/persistence/domain contracts genuinely differ.

Do not duplicate types just because each layer supposedly needs its own model.

Python dependency injection can simply be:

```
service = ProjectService(repository, logger)
```

Do not introduce:

```
Container
Registry
Provider
Resolver
ServiceLocator
DependencyGraph
```

without a real need.

Explicit construction is easier to trace.

Bad:

```
repo = services.get("project_repository")
```

Prefer explicit dependencies.

Likewise, avoid mutable module-level globals for application services/config where explicit wiring is practical.

Bad:

```
class DatabaseSingleton:
    _instance = None

    @classmethod
    def get_instance(cls):
        ...
```

unless the lifecycle genuinely requires it.

Usually the application startup layer can create one instance and pass it around.

Do not add wrapper utilities around normal context manager behavior without value.

Bad:

``` python
def safe_transaction(db):
    return TransactionContext(db)
```

when:

```
with db.transaction():
    ...
```

already expresses the operation clearly.

Do use them for real resources:

```
with open(path) as file:
async with client.stream(...) as response:
with transaction:
```

Do not replace appropriate resource management merely to reduce lines.

Be suspicious of:

``` python
@retry(...)
def everything():
```

Retries are not generic safety.

Only retry operations that are:

- transient
- idempotent or safe to repeat
- appropriate for retry semantics

Do not add retries around arbitrary business logic.

Be suspicious when functions accumulate:

```
@retry
@log_execution
@validate
@measure
@catch_errors
@authorize
@normalize
```

Decorators hide control flow.

Use them for genuinely cross-cutting concerns with stable semantics.

Do not turn basic logic into a decoration stack.

Bad:

``` python
@ensure_not_none
def process_project(...):
```

when:

```
if project is None:
    raise ProjectNotFound(...)
```

is clearer.

Explicit logic is often better than decorator magic.

Bad:

```
if project is not None:
    if project.enabled:
        if project.status == "active":
            # 50 lines
```

Prefer:

```
if project is None:
    raise ProjectNotFound(project_id)

if not project.enabled:
    return

if project.status != "active":
    return

# main logic
```

Keep the happy path obvious.

Bad:

```
if enabled is True:
```

when:

```
if enabled:
```

is equivalent.

Bad:

```
if enabled == False:
```

Prefer:

```
if not enabled:
```

Use explicit `is True` only when tri-state behavior genuinely matters.

Bad:

```
value = "a" if active else "b" if enabled else "c"
```

Prefer normal control flow.

Do not compress logic at the expense of readability.

Bad:

```
raw_domain = event.domain
trimmed_domain = raw_domain.strip()
normalized_domain = trimmed_domain.lower()
domain = normalized_domain
```

Prefer:

```
domain = event.domain.strip().lower()
```

Use intermediate names only when they clarify meaningful concepts.

Be suspicious of:

```
return list(items)
```

or:

```
copy = items[:]
```

when ownership/mutation does not require a copy.

Do not allocate defensively without a real reason.

Likewise:

```
return dict(config)
```

should have a concrete ownership reason.

Do not copy mutable structures mechanically.

Search for:

```
copy.deepcopy(...)
```

Deep copying can be expensive and usually signals unclear ownership.

Use it only when nested mutation isolation is actually required.

Do not add:

```
@lru_cache
@cache
```

to functions without understanding:

- lifecycle
- cardinality
- invalidation
- memory growth
- stale data behavior

Caching is architecture, not a free optimization.

Do not make functions async just because surrounding code is async.

Bad:

``` php
async def normalize_domain(domain: str) -> str:
    return domain.strip().lower()
```

Prefer synchronous functions for synchronous work.

Be suspicious of:

```
asyncio.create_task(...)
```

added simply to "not block."

Every background task raises questions about:

- ownership
- cancellation
- exception handling
- shutdown
- ordering
- lifetime

Use task creation deliberately.

Bad:

```
asyncio.create_task(send_event())
```

with no task tracking or error handling.

If the result matters, await it.

If fire-and-forget is intentional, ensure the application owns the task lifecycle.

Do not turn two trivial sequential calls into concurrency automatically.

Use concurrent execution when operations are independent and actually benefit from overlapping I/O.

Do not make control flow harder for theoretical speedups.

Avoid:

```
asyncio.Lock()
threading.Lock()
```

without real shared mutable state and concurrency.

Locks create lifecycle and deadlock complexity.

Protect actual races, not hypothetical ones.

Do not wrap already-async libraries in:

```
asyncio.to_thread(...)
run_in_executor(...)
```

without need.

Use thread offloading for genuinely blocking operations.

Do not introduce workers/process pools for small CPU work without evidence.

Measure first.

Simple code first.

Be suspicious of:

```
@dataclass
class Result(Generic[T]):
    value: T | None
    error: Exception | None
    success: bool
```

Python already has exceptions.

Do not emulate Rust/Go-style result handling unless the codebase deliberately uses that model.

Question:

```
str | None
Project | None
Config | None
```

when the value is actually required after construction.

Do not model required internal state as nullable purely because data initially enters incompletely.

Parse/build a valid object first.

Bad:

```
if project is None:
    return None

if project.config is None:
    return None

if project.config.domain is None:
    return None
```

when the object contract says these are required.

Fix the model.

Use `None` only for real optionality.

Bad:

```
port = value or 8080
```

when `0` might have meaning.

Bad:

```
enabled = value or True
```

Use explicit `None` handling when appropriate:

```
port = 8080 if value is None else value
```

Do not conflate falsey with missing.

Be suspicious of:

```
str(value)
int(value)
bool(value)
float(value)
```

used as "validation."

For example:

```
bool("false")
```

is `True`.

Do not silently coerce malformed external data.

Parse it according to its real contract.

Good:

```
class DeploymentStatus(StrEnum):
    PENDING = "pending"
    RUNNING = "running"
    FAILED = "failed"
```

when the valid states are closed and domain-significant.

Do not create an enum for every arbitrary string.

Be suspicious of:

```
@dataclass
class ProjectID:
    value: str
```

when a string is sufficient.

A custom type can be useful when it provides real validation or domain behavior.

Do not wrap every primitive.

Bad:

``` python
class ProjectList:
    def __init__(self, projects: list[Project]):
        self._projects = projects
```

with methods that merely proxy list behavior.

Use built-in collections unless a domain abstraction provides real value.

Before keeping custom helpers, check whether Python already has the operation.

Prefer:

```
str.strip
str.lower
pathlib.Path
collections.defaultdict
itertools
functools
dataclasses
enum
contextlib
urllib.parse
```

where appropriate.

Do not maintain custom versions of standard behavior.

Audit modules/packages called:

```
utils.py
helpers.py
common.py
shared.py
misc.py
base.py
core.py
```

These often collect unrelated functions.

Delete trivial helpers.

Move domain-specific logic to the domain that owns it.

Do not create another generic utility module during cleanup.

Do not create a new file for every class/function.

Bad:

```
domain_parser.py
domain_normalizer.py
domain_validator.py
domain_converter.py
```

for four tiny functions.

Group cohesive functionality.

File count is not architecture quality.

A module can contain several closely related functions.

Do not interpret "single responsibility" as "one function per file."

Optimize for discoverability.

Be suspicious of:

```
HANDLERS = {}
register_handler(...)
register_service(...)
PLUGIN_REGISTRY = {}
```

when a normal `match`/dictionary literal/import is sufficient.

Use dynamic registration only when extensibility is genuinely required.

Bad:

```
handler = registry.resolve(event.type)
return handler.process(event)
```

when:

```
match event.type:
    case "insert":
        return handle_insert(event)
    case "delete":
        return handle_delete(event)
```

is clearer.

Do not turn static cases into plugin architecture.

Three branches do not automatically need:

```
BaseStrategy
InsertStrategy
DeleteStrategy
ReplaceStrategy
StrategyFactory
```

Use ordinary Python control flow when easier to understand.

Bad:

```
processor(value, lambda x: normalize(x))
```

when:

```
processor(value, normalize)
```

is enough.

Or simply:

```
normalize(value)
```

if the abstraction itself is unnecessary.

Do not turn complex business logic into dense comprehensions.

Bad:

```
result = {
    x.id: transform(x)
    for x in items
    if x.enabled and x.config and x.config.valid
}
```

when a loop would make failure cases and rules clearer.

Comprehensions are for simple transformations.

Bad:

```
return next((x for x in values if x.id == id_), None)
```

is fine when obvious.

But do not compress multi-step business logic into nested expressions simply to save lines.

Readability first.

Be suspicious of:

```
map(...)
filter(...)
reduce(...)
partial(...)
```

when a simple loop is clearer.

Python often reads better with comprehensions or direct loops.

Do not optimize for abstract functional style.

Bad:

```
list(map(lambda x: x.id, projects))
```

Prefer:

```
[project.id for project in projects]
```

Use idiomatic Python.

Bad:

``` php
def is_empty(value: str) -> bool:
    return len(value) == 0
```

Prefer:

```
if not value:
```

when semantics match.

Do not wrap obvious built-ins for no reason.

Bad:

```
re.sub(r"^\s+|\s+$", "", domain)
```

Prefer:

```
domain.strip()
```

Use regex for regex-shaped problems.

Do not use dynamic code execution to solve configuration, expression, or dispatch problems unless the feature explicitly requires it and security implications are understood.

Prefer explicit parsing.

Do not patch classes/functions at runtime to avoid proper dependency design.

Monkey patching may be appropriate in tests or specialized libraries.

It should not be normal application architecture.

Metaclasses are rarely required in ordinary application code.

Be highly suspicious of introducing:

```
class FooMeta(type):
    ...
```

for registration, validation, or convenience.

Prefer normal classes/decorators/functions.

Likewise, do not introduce custom descriptors for basic validation or computed fields when properties/dataclasses/models solve the problem more clearly.

Bad:

``` php
class Project:
    @property
    def id(self) -> str:
        return self._id
```

when there is no invariant or encapsulation need.

Use plain attributes where appropriate.

Python does not need Java-style getters/setters.

Bad:

```
project.get_id()
project.set_id(id_)
```

for ordinary attributes.

Prefer:

```
project.id
```

unless access has real behavior.

Do not use:

```
self._project_id
```

plus a property purely for encapsulation theater.

Python's conventions are enough.

Use private-ish fields when they represent internal implementation state.

For Mongo/PyMongo:

Bad:

```
document: dict[str, Any]
domain = document.get("domain")

if isinstance(domain, ObjectId):
    return str(domain)
```

when the document schema is known.

Use a model/TypedDict:

```
class DNSDocument(TypedDict):
    domain: ObjectId
```

then:

```
str(document["domain"])
```

Or use an ODM model if the project already does.

If SQLAlchemy/Django models define:

```
project.id: str
project.enabled: bool
```

do not repeatedly runtime-check them inside business logic.

Trust the ORM model unless the field genuinely allows null.

Bad:

```
repository.find(
    collection="projects",
    filters={"id": project_id},
    projection=None,
    options={}
)
```

when the application has a clear domain operation.

Prefer:

```
project_repository.get(project_id)
```

Do not make internal APIs mimic a generic database driver unless generic behavior is genuinely needed.

Avoid:

```
Repository
→ DAO
→ Store
→ DatabaseClient
→ Session
```

for simple persistence.

Use the minimum layering that gives useful testability and separation.

Do not build elaborate:

```
UnitOfWork
TransactionManager
TransactionScope
TransactionProvider
```

around a small amount of transaction code unless the application genuinely benefits.

Use the ORM/database's native transaction API directly where clearer.

Bad:

```
class QueueMessage:
    event: str
    data: dict[str, Any]
```

with downstream code doing:

```
if message.event == "domain.map":
    data = as_domain_map_event(message.data)
```

Prefer event-specific parsing at the boundary.

Example:

```
class DomainMapEvent(BaseModel):
    event: Literal["domain.map"]
    project_id: str
    domain: str
```

Or use discriminated unions if the project's validation library supports them.

Parse JSON once.

Validate once.

Convert into the domain representation once.

Do not repeatedly do:

```
json.loads(...)
dict(...)
model_validate(...)
asdict(...)
```

across layers.

Bad:

```
data = json.loads(model.model_dump_json())
```

or:

```
payload = json.loads(json.dumps(data))
```

just to convert structures.

Use direct conversions or actual typed objects.

With Pydantic, do not constantly turn models back into raw dicts:

```
service.run(payload.model_dump())
```

if the service could accept the model/type directly.

Dump only at serialization or integration boundaries.

Bad:

```
service.create_project({
    "project_id": project_id,
    "region": region,
})
```

when:

```
service.create_project(project_id, region)
```

or a meaningful request object is clearer.

Use parameter objects when the values form a real concept or the parameter list is substantial.

Do not pass huge context objects where only two fields are needed.

Bad:

``` php
def sync_project(payload: ProjectPayload) -> None:
    project_id = payload.project_id
    rate_limit = payload.rate_limit
```

if only those fields matter.

Prefer:

``` php
def sync_project(project_id: str, rate_limit: int) -> None:
```

unless the payload itself is the meaningful domain concept.

Bad:

``` php
def create_project(options: dict[str, Any]) -> Project:
```

Prefer explicit parameters or a concrete model.

Generic option dictionaries push validation problems downstream.

Bad:

```
deploy(
    project,
    force=True,
    skip_cache=False,
    async_mode=True,
    validate=False,
)
```

If flags create meaningfully different operations, consider separate functions or a clear options model.

Do not create cryptic combinations of booleans.

At the same time, do not turn:

```
deploy(project_id)
```

into:

```
DeployCommand(
    options=DeployOptions(
        behavior=DeployBehavior(...)
    )
)
```

without a real reason.

Avoid both extremes.

Avoid:

```
logger.debug("Entering function")
logger.debug("Validating input")
logger.debug("Calling repository")
logger.debug("Repository returned")
logger.debug("Returning result")
```

Log:

- failures
- important state transitions
- external operations
- debugging information with real operational value

Do not narrate code execution.

If the codebase uses structured logging:

```
logger.info(
    "project deployed",
    extra={"project_id": project_id},
)
```

follow existing conventions.

Do not introduce a new logging framework during cleanup.

Delete comments like:

```
# Check if project exists
if project is None:
# Convert domain to lowercase
domain = domain.lower()
```

Keep comments for:

- business rules
- quirks
- invariants
- external constraints
- non-obvious reasoning

Comments should explain why.

Bad:

``` php
def get_project(project_id: str) -> Project:
    """Get a project."""
```

This adds nothing.

Keep docstrings for public APIs, complex semantics, parameters with non-obvious contracts, or behavior worth documenting.

Do not add huge Google/Numpy-style docstrings to obvious private helpers.

Example of unnecessary ceremony:

``` php
def normalize_domain(domain: str) -> str:
    """
    Normalize the domain name.

    Args:
        domain: The domain name.

    Returns:
        The normalized domain name.
    """
```

Prefer self-explanatory code.

Apply anti-slop rules to tests too.

Be suspicious of:

```
TestDataBuilder
MockFactory
FixtureFactory
ScenarioBuilder
BaseTestCase
IntegrationTestHelper
```

for simple tests.

Prefer direct setup and pytest fixtures where useful.

Do not mock pure internal code unnecessarily.

Mock real external boundaries where isolation matters:

- network
- filesystem
- third-party APIs
- expensive infrastructure

Use real domain objects for internal logic when practical.

Good:

```
@pytest.mark.parametrize(
    ("value", "expected"),
    [
        ("EXAMPLE.COM", "example.com"),
        (" example.com ", "example.com"),
    ],
)
def test_normalize_domain(value: str, expected: str) -> None:
    assert normalize_domain(value) == expected
```

Do not build a testing DSL for three cases.

Do not create:

```
BaseServiceTest
BaseRepositoryTest
BaseIntegrationTest
```

unless there is substantial common lifecycle behavior.

Prefer fixtures and composition.

Bad:

``` python
def safe_mock_return(mock: Mock, default=None):
```

Use the mocking library normally.

Do not invent abstraction around standard test tooling without need.

Do not remove validation for:

- HTTP requests
- CLI arguments
- queue payloads
- config/env vars
- webhooks
- untrusted JSON
- external APIs
- schemaless database records
- user input
- file contents

That is where defensive programming belongs.

Do not remove:

- network timeout handling
- database errors
- not-found cases
- transaction rollback
- file-not-found handling
- permission errors
- subprocess failures
- cancellation handling
- API-specific exceptions
- security checks

This is not a request to make code fragile.

The distinction is:

**Defend against external uncertainty, not against correctly typed internal code.**

This is not a cleanup:

```
value = cast(str, data["domain"])
```

becoming:

```
value = data.get("domain")

if value is None:
    return ""

if not isinstance(value, str):
    return ""

if len(value) == 0:
    return ""

return value
```

if the actual contract says `domain` is required and is a string.

The correct fix is:

```
@dataclass
class DomainEvent:
    domain: str
```

and then:

```
event.domain
```

Whenever you see:

```
safe_x
as_x
normalize_x
extract_x
convert_x
resolve_x
ensure_x
coerce_x
```

trace the value upstream.

Ask:

1. Why is this value not already typed?
2. Where does it enter the application?
3. Is that where validation belongs?
4. Can downstream code receive a concrete type?
5. Can the helper disappear entirely?

Always prefer fixing the earliest sensible point in the data flow.

Search the repository for:

```
Any
dict[str, Any]
Mapping[str, Any]
object
cast(
isinstance(
hasattr(
getattr(
setattr(
vars(
__dict__
inspect.
type(
try:
except Exception
except:
pass
return None
return {}
return []
return ""
.get(
or {}
or []
or ""
deepcopy
Base
Abstract
Mixin
Manager
Processor
Factory
Builder
Resolver
Converter
Mapper
Validator
Helper
Utils
Protocol
ABC
Generic
TypeVar
create_task
gather
to_thread
run_in_executor
retry
lru_cache
```

Do not automatically remove every match.

Use them as signals to inspect for unnecessary complexity.

Especially review directories/features containing combinations like:

```
base.py
interfaces.py
protocols.py
factory.py
builder.py
mapper.py
converter.py
validator.py
resolver.py
manager.py
processor.py
helpers.py
utils.py
service.py
repository.py
```

for one small feature.

Determine whether each layer has real behavior.

Collapse meaningless ones.

Before adding or keeping code, ask:

Is this defending against something that can genuinely happen here?

If no, remove it.

Ask:

Is this complexity caused by an overly broad type?

If yes, fix the type.

Ask:

Does this helper represent a real concept?

If no, inline it.

Ask:

Does this abstraction reduce total complexity?

If no, delete it.

Ask:

Is this dynamic Python because the problem is actually dynamic, or because the code does not know its own types?

If the latter, fix the model.

Ask:

Would plain Python be easier to understand?

If yes, use plain Python.

Prefer:

``` php
async def handle_domain_map(
    event: DomainMapEvent,
) -> None:
    domain = event.domain.strip().lower()

    await domain_service.map(
        project_id=event.project_id,
        domain=domain,
    )
```

over:

``` php
async def handle_domain_map(
    raw_data: Any,
) -> None:
    data = ensure_dict(raw_data)

    project_id = safe_string(
        data.get("project_id")
    )

    domain = normalize_value(
        data.get("domain")
    )

    if not project_id or not domain:
        return

    payload = DomainMappingPayload.from_dict(
        {
            "project_id": project_id,
            "domain": domain,
        }
    )

    await domain_manager.process_mapping(payload)
```

Before editing Python code:

1. Identify the trusted and untrusted boundaries.
2. Determine the actual data shapes.
3. Check whether `Any` /generic dictionaries are necessary.
4. Understand whether `None` is genuinely valid.
5. Inspect whether abstractions have real callers/implementations.
6. Prefer fixing data models upstream instead of adding local guards.
7. Do not add new helpers before understanding why the existing type is broad.

Before finishing any Python change, inspect the diff.

For every added:

- helper
- class
- protocol
- base class
- mixin
- factory
- builder
- wrapper
- fallback
- `isinstance`
- `getattr`
- `Any`
- `dict[str, Any]`
- `try/except`
- nullable type
- decorator

ask:

1. Does this handle a state that can genuinely occur?
2. Am I compensating for bad typing upstream?
3. Could this code be direct instead?
4. Did I add another abstraction layer?
5. Does this helper have a real reusable concept?
6. Am I hiding invalid input behind an empty value?
7. Am I swallowing an error?
8. Did I introduce dynamic behavior where the shape is known?
9. Did the change increase total complexity?
10. Could any newly added code simply be deleted?

If yes, simplify before completing the task.

The codebase should trend toward:

- fewer `Any` values
- fewer generic dictionaries
- fewer runtime type checks
- fewer `.get()` chains
- fewer silent fallbacks
- fewer broad `except Exception`
- fewer tiny helper functions
- fewer mapper/converter classes
- fewer base classes and mixins
- fewer factories/builders
- fewer unnecessary protocols
- fewer pass-through layers
- more precise models
- validation concentrated at boundaries
- direct attribute access
- explicit business logic
- idiomatic Python
- easy-to-follow control flow

The important metric is not line count alone.

The important metric is:

**Can another engineer understand the behavior without navigating defensive machinery and unnecessary abstractions?**

Do not transform:

```
validated typed input
→ direct business logic
```

into:

```
Any
→ isinstance
→ getattr
→ safe helper
→ converter
→ fallback
→ wrapper
→ manager
→ actual operation
```

The desired flow is:

```
untrusted input
→ parse/validate once
→ precise Python type
→ straightforward business logic
```

The overriding principle is:

**Make uncertainty explicit at the boundary. Keep trusted Python code simple, typed, direct, and boring.**
