| name | brokk-modeling-inconsistencies |
| description | Use when asked to find modeling problems, confusing logic, or misleading naming in a codebase - looks for concepts that contradict the domain, logic that doesn't match what a function claims to do, and methods too complex to reason about |
brokk-modeling-inconsistencies
Overview
Find places where the code's model of the domain is wrong, confused, or self-contradicting. This is not about code style or error handling patterns — it's about semantic correctness: does the code say what it means, and does it mean what it says?
The core question for every finding: "Would a new developer be misled by this?"
Prerequisites
rg --version 2>/dev/null || echo "rg MISSING"
Dimension 1 — Misleading Names
Names that contradict what something actually does are the most dangerous modeling problem — they cause correct-looking bugs.
Functions that lie about what they do
Read function signatures and their bodies. Flag any where:
- The name says "get" but the function also writes, deletes, or has side effects
- The name says "validate" but it also transforms or persists data
- The name says "create" but it may return an existing record
- The name includes "safe", "clean", or "simple" but the body is neither
- A boolean function (
isX, hasX, canX) returns something other than a boolean, or has side effects
- A
find* / search* function raises/panics instead of returning empty/nil when nothing found
rg -n "^(func|def|function)\s+(is|has|can|should|will)[A-Z_]" --type go
rg -n "^def (is_|has_|can_|should_)" --type py
rg -n "^(export )?(function|const)\s+(is|has|can)[A-Z]" --type ts
Concepts with two names (semantic duplicates)
The same real-world thing named differently in different parts of the codebase creates an implicit lie — readers assume two names mean two things.
Scan for synonym clusters. If more than one term from a cluster appears as a type, field, or module name, investigate whether they refer to the same concept:
| Cluster | Synonyms to check |
|---|
| Identity | user, account, member, principal, identity, profile |
| Operation | job, task, work, request, operation, command |
| Result | result, response, output, reply, payload |
| Error state | error, failure, fault, problem, issue, exception |
| Removal | delete, remove, destroy, purge, archive, cancel |
| Retrieval | get, fetch, load, find, query, retrieve, read |
rg -n "^(type|class|struct|interface)\s+(Job|Task)\b" --type go
rg -n "^class (Job|Task)\b" --type py
If both exist: read both definitions. Are they the same concept? If so, flag as a semantic duplicate that should be unified.
Names that invert or obscure the domain concept
rg -n "(disable|not|no|un|without)[A-Z_]" -l | head -20
Flag any name where understanding the behaviour requires mentally inverting the name.
Dimension 2 — Logic That Contradicts the Model
Read key business logic files and look for:
Conditional logic that undoes what the caller expects
- A function named
save() that sometimes returns without saving (with no documented reason)
- A function named
sendNotification() that has a silent early return based on an undocumented flag
- A
retry() wrapper that doesn't retry in certain conditions that aren't obvious from the name
Look for invisible exits — early return or continue statements in the middle of a business function that are easy to miss:
rg -n "^\s+return " --type go -c | sort -t: -k2 -rn | head -20
rg -n "^\s+return " --type py -c | sort -t: -k2 -rn | head -20
Read the top offenders and check if the early returns represent undocumented domain rules.
Domain rules buried in infrastructure
Business rules should be in domain/service code, not scattered across:
- Database query filters that encode business eligibility rules
- HTTP middleware that makes business decisions
- Serialisers/formatters that apply business transformations
rg -n "(status|role|tier|plan|permission)" \
--glob "*middleware*" --glob "*filter*" --glob "*serializ*" \
--glob "*format*" --glob "*marshal*"
Read each hit — is this a business rule that belongs elsewhere?
State that can become inconsistent
Look for entities modelled with fields that should always agree but nothing enforces the agreement:
rg -n "(isActive|is_active|enabled|disabled)" --type go
rg -n "(status|state)\s*[=:]\s*['\"]" --type py | head -20
Example red flag: an entity with both status: "cancelled" and isActive: true as separate fields — they can disagree.
Dimension 3 — Concepts Modelled at the Wrong Level
The same concept at two abstraction levels
rg -n "\bUserId\b|\buser_id\b" --type go | head -30
If an ID, money amount, or status value appears both as a primitive (string, int) in some places and as a value object/struct in others, the model is split — bugs occur at the seam.
Leaking implementation details into domain names
Domain names should describe the business, not the storage or transport:
UserTable, OrderRow, ProductDocument — storage leaking into domain
UserDTO, OrderPayload, ProductRequest used as the primary domain concept rather than as a boundary type
rg -n "(Table|Row|Document|Record|DTO|Payload|Request|Response)\b" \
--glob "!*test*" --glob "!*spec*" | head -30
Read each hit — is this a boundary/transport type, or is it being used as the core domain model?
Primitive obsession — important domain concepts not modelled as types
Look for patterns where a concept that has domain rules is passed around as a raw primitive:
rg -n "(price|amount|cost|fee|balance|total)\s*:\s*(float|double|number|Float|Double)" | head -20
rg -n "(date|timestamp|createdAt|due_date)\s*:\s*(str|string|String)\b" | head -20
rg -n "(email|phone|postcode|zipcode)\s*:\s*(str|string|String)\b" | head -20
Dimension 4 — Methods Too Complex to Reason About
A method that cannot be understood in one reading cannot be verified to correctly implement the domain model.
Cyclomatic complexity — too many branches
rg -n "\b(if|switch|case|else if|elif|catch|rescue|when)\b" --type go -c \
| sort -t: -k2 -rn | head -20
Read the top files. Look for functions where the number of branches makes it impossible to mentally trace all paths.
Methods that do more than one thing
For each complex method found, apply the "and test": can you describe what it does without using the word "and"? If not, it models more than one concept.
Examples:
validateAndSave() — two operations, two potential failure points, two reasons to change
- A function that fetches data, transforms it, and persists it — three concerns, one name
Flag when the same function handles both the happy path and multiple exceptional states in deeply nested logic
rg -n "^(\t{4,}| )" --type go -l | head -20
rg -n "^(\t{4,}| )" --type py -l | head -20
Read the flagged functions — deep nesting usually means the function is making too many domain decisions in one place.
Output Format
## Modeling Inconsistencies Report
### Misleading Names
| Name | Location | What it claims | What it actually does |
|------|----------|---------------|----------------------|
| `getOrCreate()` | src/users/repo.py:44 | retrieval | creates if absent — side effect not obvious |
### Semantic Duplicates (same concept, two names)
| Concept | Names in use | Locations |
|---------|-------------|-----------|
| The user identity | User, Account, Member | 3 packages |
### Logic vs Model Contradictions
| Issue | Location | Detail |
|-------|----------|--------|
| Silent no-op in save() | src/orders/service.py:88 | Returns without saving if `draft=True`, undocumented |
### Wrong Abstraction Level
| Issue | Location | Detail |
|-------|----------|--------|
| Money as float64 | pkg/billing/invoice.go:14 | No rounding or currency type |
### Too Complex to Reason About
| Method | Location | Problem |
|--------|----------|---------|
| processOrder() | src/orders/handler.py:112 | 8 early returns, 4 nested conditions — cannot verify correctness |
### Priority
1. [Most misleading / highest risk of bugs]
2. ...
What This Skill Does NOT Cover
- Code style (naming conventions like camelCase vs snake_case) → see brokk-code-smells
- Error handling consistency → see brokk-code-smells
- Security vulnerabilities → see brokk-security-scan
- Missing tests → see brokk-untested-paths
Common Mistakes
| Mistake | Fix |
|---|
| Flagging naming style differences | Only flag names that actively mislead about behaviour or domain concept |
| Flagging every long function | Only flag when length makes the domain logic unverifiable |
| Missing semantic duplicates | Always scan for synonym clusters — these are the hardest bugs to find |
| Stopping at surface names | Read function bodies — the lie is often inside, not in the name |