distill: 48 cross-project best-practices from 2026-07 reflection sweep

Promotions from reflecting 21 projects' session logs (incl. agent-runtimes
122-log drain). Adds coverage across networking (eBPF VIP/VPN SNAT/VLAN
bridge/forward-auth preflight/ingress TLS), kubernetes (CSI hotplug/PodSecurity
debug/self-managed GitOps/runtime annotations), CI (dispatch tokens/runner
death/base image), git (CI-rebase/shallow reset/PR governance), python (async
session pool/httpx redirects/logging), TDD (AsyncMock/xfail lifecycle),
api-integration (SDK parse/token-scope 404/schema probing), plus docker,
scripting, debugging, security-architecture, secrets, react, octopus.

State: .distill-state.json refreshed with current HEADs + 5 newly-tracked projects.
This commit is contained in:
Paul O'Reilly
2026-07-02 15:57:42 +12:00
parent 5e67cbcfbb
commit 7e348f5ee3
16 changed files with 577 additions and 57 deletions

View File

@@ -203,6 +203,8 @@ requires = ["setuptools>=68"]
build-backend = "setuptools.build_meta"
```
**(d) New `[project.scripts]` console entry point not found after adding it.** A `command not found` for a script declared in `[project.scripts]`, despite the declaration being correct. Editable installs only register console scripts that existed *at install time* — adding an entry point after `pip install -e .` doesn't retroactively create the shim. Re-run `pip install -e .` in the active venv to register any newly added entry point.
## Bridging `threading.Event` to `asyncio` — Use a Polling Bridge
When an HTTP server or other handler running in a **background thread** needs to signal an `asyncio` controller loop (e.g., webhook handler waking a reconciler), a plain `threading.Event.set()` cannot directly wake `asyncio.wait_for` or `asyncio.sleep` in the event-loop thread. The event loop only wakes for tasks it scheduled.
@@ -285,3 +287,19 @@ spec.loader.exec_module(module)
```
The `sys.modules` registration must happen before `exec_module` — otherwise any `import my_tool` inside the loaded module creates a second, distinct module object.
## `httpx` Credential-Carrying Clients: Disable Redirect-Following
`httpx.Client(follow_redirects=True)` (the default) forwards the `Authorization` header to the redirect target on a 302 — leaking a bearer/OIDC token to whatever host the redirect points at. Set `follow_redirects=False` unconditionally on any client that carries credentials. Related: `httpx.MockTransport` fails on relative URLs, so always pass an explicit `base_url=` in tests; and a `base_url` with a path prefix (`https://x/api`) is silently dropped when the request path is absolute (`/v1/items``https://x/v1/items`) — end `base_url` with `/` and `lstrip("/")` the path before joining.
## Construct a Fresh HTTP Client Per Call for Per-Request Auth Headers
When each request needs its own headers (HMAC signature + timestamp, one-time nonce, per-call bearer), do NOT mutate or evolve a shared client. httpx's `Client.with_headers()` evolves a copy that still shares the underlying transport, so per-request headers leak across calls and race under concurrency. Build a fresh `Client(headers=...)` per call. Related header trap: `dict(request.headers).get("Authorization")` returns `""` — casting httpx's case-insensitive multidict to a plain dict loses the header; use `request.headers.get(...)` directly.
## SQLAlchemy async: Always Use `async with session_factory()` — Never a Raw Session
A raw `AsyncSession` created as `session = session_factory()` (not `async with`) that goes out of scope without `commit()`/`rollback()`/`close()` leaves psycopg3's implicit transaction dangling. The GC cannot async-close it, so the pool's checked-out counter never decrements — the slot becomes a permanent ghost. Once all `pool_size + max_overflow` slots are ghost-occupied, every new connection request blocks forever: health checks time out, the liveness probe kills the pod, and it crash-loops. Precursor signal in logs: SAWarning "garbage collector is trying to clean up non-checked-in connection." Fix: route every session through `async with session_factory() as session:` (or a `get_session()` helper). Audit every call site that calls `session_factory()` directly — the crash is invisible in local/memory-store testing and only bites production.
## `logging` Reserved LogRecord Attributes Crash the Formatter
Passing a reserved key in `logger.info(msg, extra={...})` raises `KeyError("Attempt to overwrite 'name' in LogRecord")`. Reserved names include `name`, `msg`, `args`, `levelname`, `levelno`, `pathname`, `filename`, `module`, `funcName`, `lineno`, `created`, `process`, `thread`, `message`, `asctime`, and the rest of the LogRecord fields. Rename your keys (e.g. `resource_name`). Worse failure mode: if this log line sits in a success path wrapped by an outer `try/except Exception`, the KeyError makes a *successful* operation look like a failure and rolls back / skips subsequent work. Rule: logging is best-effort — never put load-bearing logic in a log call, and audit `extra=` keys for reserved-name collisions before shipping.