feat(directives): harvest 7 directives from python.md §17.1-17.7 (banned patterns + boundary exception)

This commit is contained in:
ed
2026-07-02 21:49:13 -04:00
parent 41c8678b28
commit f4dfb84681
7 changed files with 172 additions and 0 deletions
+22
View File
@@ -0,0 +1,22 @@
# ban_any_type — v1
**Why this iteration:** Lifted verbatim from `conductor/code_styleguides/python.md` §17.2 (lines 267-277).
This is the baseline encoding — the imperative-ban style currently in production.
Future variants will test alternative encodings (rationale-first, before/after, tabular) against this baseline.
**Source:** `conductor/code_styleguides/python.md:267-277`
---
### 17.2 Banned: `Any`
```python
# BANNED:
def _to_typed_tool_call(tc: Any) -> ToolCall:
return ToolCall(id=getattr(tc, "id", "") or "", ...)
# CORRECT:
def _parse_wire_tool_call(wire: dict[str, Any]) -> ToolCall:
"""Boundary: parse MCP wire dict to typed ToolCall."""
return ToolCall.from_dict(wire)
```
+28
View File
@@ -0,0 +1,28 @@
# ban_dict_any — v1
**Why this iteration:** Lifted verbatim from `conductor/code_styleguides/python.md` §17.1 (lines 247-265).
This is the baseline encoding — the imperative-ban style currently in production.
Future variants will test alternative encodings (rationale-first, before/after, tabular) against this baseline.
**Source:** `conductor/code_styleguides/python.md:247-265`
---
### 17.1 Banned: `dict[str, Any]`
```python
# BANNED:
def process(event: dict[str, Any]) -> None:
if event.get("kind") == "tool_call":
# BANNED:
flat: dict[str, Any] = project_manager.flat_config(...)
# CORRECT:
def process(event: CommsLogEntry) -> None:
if event.kind == "tool_call":
# CORRECT (boundary only):
def _parse_wire(raw: str) -> Metadata:
return Metadata.from_dict(tomllib.loads(raw))
```
@@ -0,0 +1,21 @@
# ban_dict_get_on_known_fields — v1
**Why this iteration:** Lifted verbatim from `conductor/code_styleguides/python.md` §17.6 (lines 340-350).
This is the baseline encoding — the imperative-ban style currently in production.
Future variants will test alternative encodings (rationale-first, before/after, tabular) against this baseline.
**Source:** `conductor/code_styleguides/python.md:340-350`
---
### 17.6 Banned: `.get('field', default)` on a `dict[str, Any]`
```python
# BANNED:
tier = entry.get('source_tier', 'main')
model = entry.get('model', 'unknown')
# CORRECT (direct attribute access on the typed dataclass):
tier = entry.source_tier
model = entry.model
```
@@ -0,0 +1,21 @@
# ban_getattr_dispatch — v1
**Why this iteration:** Lifted verbatim from `conductor/code_styleguides/python.md` §17.5 (lines 328-338).
This is the baseline encoding — the imperative-ban style currently in production.
Future variants will test alternative encodings (rationale-first, before/after, tabular) against this baseline.
**Source:** `conductor/code_styleguides/python.md:328-338`
---
### 17.5 Banned: `getattr(x, 'field', default)` for type dispatch
```python
# BANNED:
tool_id = getattr(tc, "id", "") or ""
tool_name = getattr(tc.function, "name", "") or ""
# CORRECT:
tool_id = tc.id
tool_name = tc.function.name
```
@@ -0,0 +1,36 @@
# ban_hasattr_dispatch — v1
**Why this iteration:** Lifted verbatim from `conductor/code_styleguides/python.md` §17.4 (lines 300-326).
This is the baseline encoding — the imperative-ban style currently in production.
Future variants will test alternative encodings (rationale-first, before/after, tabular) against this baseline.
**Source:** `conductor/code_styleguides/python.md:300-326`
---
### 17.4 Banned: `hasattr()` for entity type dispatch
```python
# BANNED:
def handle_event(self, event: Metadata) -> None:
if hasattr(event, 'tool_calls'):
# tool call path
elif hasattr(event, 'source_tier'):
# mma path
elif hasattr(event, 'path'):
# file path
# CORRECT (typed Union dispatch):
def handle_event(self, event: CommsLogEntry | FileItem | HistoryMessage) -> None:
if isinstance(event, CommsLogEntry):
# mma path
elif isinstance(event, FileItem):
# file path
elif isinstance(event, HistoryMessage):
# tool call path
# CORRECT (preferred — refactor so no dispatch is needed):
def _handle_comms_entry(self, event: CommsLogEntry) -> None: ...
def _handle_file_item(self, event: FileItem) -> None: ...
def _handle_history(self, event: HistoryMessage) -> None: ...
```
@@ -0,0 +1,31 @@
# ban_optional_returns — v1
**Why this iteration:** Lifted verbatim from `conductor/code_styleguides/python.md` §17.3 (lines 279-298).
This is the baseline encoding — the imperative-ban style currently in production.
Future variants will test alternative encodings (rationale-first, before/after, tabular) against this baseline.
**Source:** `conductor/code_styleguides/python.md:279-298`
---
### 17.3 Banned: `Optional[T]` returns
```python
# BANNED:
def find_ticket(self, id: str) -> Optional[Ticket]:
for t in self.active_tickets:
if t.id == id: return t
return None # ← silent failure; consumer has to None-check
# CORRECT (Result pattern):
def find_ticket(self, id: str) -> Result[Ticket]:
for t in self.active_tickets:
if t.id == id: return Result(data=t)
return Result(data=NIL_TICKET, errors=[ErrorInfo(...)]) # drain point handles
# CORRECT (NIL_T sentinel — preferred when consumer just reads fields):
def find_ticket(self, id: str) -> Ticket:
for t in self.active_tickets:
if t.id == id: return t
return NIL_TICKET # zero-initialized frozen dataclass; safe to read fields
```
@@ -0,0 +1,13 @@
# boundary_layer_exception — v1
**Why this iteration:** Lifted verbatim from `conductor/code_styleguides/python.md` §17.7 (lines 352-354).
This is the baseline encoding — the imperative-ban style currently in production.
Future variants will test alternative encodings (rationale-first, before/after, tabular) against this baseline.
**Source:** `conductor/code_styleguides/python.md:352-354`
---
### 17.7 The one exception: the boundary layer
The ONLY place these patterns are allowed is at the literal wire boundary — the function that calls `tomllib.load()`, `json.loads()`, or a vendor SDK's response parser. The boundary is 2-3 functions per file. Every consumer IMMEDIATELY converts to a typed dataclass via `from_dict()`.