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

@@ -52,6 +52,23 @@ Every script that modifies state should support `--dryrun` / `-n`:
- **Order matters in sed/regex transformation pipelines.** Process more specific patterns before general ones. For example, if both `![[image.png]]` and `[[page]]` are valid patterns, process the image embed first — otherwise the general wikilink regex matches the inner `[[image.png]]` and the `!` prefix is left orphaned.
- **Bare `except: pass` swallows `SystemExit` in Python.** `sys.exit(0)` inside a bare `except: pass` block is captured as a `SystemExit` exception and silently swallowed — the script continues instead of exiting. Use specific exception types in except clauses, or use `break`/`return` for loop early-exit, or re-raise after checking `isinstance(e, SystemExit)`. Applies to any script with loops that short-circuit on a condition inside exception handling.
- **Never use `GROUPS` (or other reserved names) as a bash variable.** `GROUPS` is pre-set by bash completion and session initialisation with numeric group IDs — assignment appears to succeed but the pre-existing value often persists in sourcing contexts, producing bizarre "array iterates over 1000, 24, 27..." bugs. Other reserved/built-in names to avoid: `UID`, `EUID`, `PWD`, `OLDPWD`, `SHLVL`, `RANDOM`, `SECONDS`, `LINENO`, `PIPESTATUS`, `IFS`. Prefix project variables (`PROJECT_GROUPS`, `TEMPLATE_SLUGS`).
- **Inline `VAR=val cmd "$VAR"` expands the pre-existing value, not the new one.** Bash inline env-var assignment sets `VAR` for the child process, but `$VAR` in argument position is expanded by the **calling** shell using its existing (often empty) value. The trap:
```bash
CP_TOKEN=$(get_token) curl -H "Authorization: Bearer $CP_TOKEN" ... # sends empty header
```
The Authorization header is empty because `$CP_TOKEN` is expanded before `CP_TOKEN=$(get_token)` takes effect. **Fixes:**
```bash
export CP_TOKEN=$(get_token) # set on a prior line
curl -H "Authorization: Bearer $CP_TOKEN" ...
# — or —
curl -H "Authorization: Bearer $(get_token)" ... # inline substitution at use site
```
Doesn't affect Python subprocesses launched with `env=...` because `os.environ` reads at runtime, not at command-parse time. Costs ~30 minutes per occurrence; common in CLI-tool authentication wrappers. See [Secrets Management](secrets-management.md) "Never Source .env Files" for the related safe-parser pattern when handling `.env`-style files.
- **`git mv <src> <dest>/<sub>` won't create missing parent directories.** `git mv admin static/admin` fails with `renaming 'admin' failed: No such file or directory` when `static/` doesn't exist yet, even though `admin/` does. Create the parent first: `mkdir static && git mv admin static/admin`.
## Grep All Consumers Before Removing or Keeping a Field
Before deleting — or deciding to keep — a config field, env var, or interactive prompt, grep every consumer across the tree (`grep -r VAR_NAME .` / `~`). Two outcomes: (1) dead fields accumulate silently when nothing reads them — the grep proves they're unused and safe to remove; (2) for fields you keep or rename, the grep enumerates every downstream file needing a matching edit (templates, status lines, other scripts), so you don't ship a half-applied rename. Auditing consumers is cheaper than shipping a change that leaves orphaned references.
## JSON Construction in Scripts