9ebc9c8868
---ci--- project: atelier phase: 6 milestone: v0.3 status: complete requirements: covered: [ATELIER-60..91] partial: [] ---/ci---
227 lines
13 KiB
Markdown
227 lines
13 KiB
Markdown
# Anti-Patterns
|
||
|
||
> A catalog of violations. Each entry names the principle it breaches. Use this to recognize and reject patterns on sight.
|
||
|
||
## How to Use
|
||
|
||
When you see a pattern listed here, it is a defect. Cite the principle it violates and require a fix. These are not "to be reviewed later"; they are rejected on sight.
|
||
|
||
## Core Anti-Patterns (C1–C8)
|
||
|
||
| Anti-Pattern | Breaches | Why |
|
||
|--------------|----------|-----|
|
||
| Code that "mostly works" | C1 Correctness | Mostly correct is incorrect |
|
||
| `function doStuff()` | C2 Clarity | Name reveals nothing |
|
||
| A 500-line function | C3 Simplicity | Complexity is a liability |
|
||
| Config in a distant repo, read silently | C4 Locality | Coupling you cannot see |
|
||
| A migration with no `down` | C5 Reversibility | Irreversible bet |
|
||
| A component reading global state implicitly | C6 Composability | Hidden dependency |
|
||
| A service with no logs | C7 Observability | Cannot debug what you cannot see |
|
||
| Loading all records into memory | C8 Economy | Unbounded = OOM |
|
||
|
||
## Domain Anti-Patterns
|
||
|
||
### UI/UX
|
||
| Anti-Pattern | Breaches | Why |
|
||
|--------------|----------|-----|
|
||
| Image without `alt` | P2 Accessibility | Disqualifying |
|
||
| "Delete" with no confirmation | P5 Forgiveness | Irreversible surprise |
|
||
| `color: #3b82f6` in a component | P8 Consistency (via tokens) | Bypasses design system |
|
||
| "Submit" on a delete button | P3 Clarity | Wrong verb |
|
||
| Layout shift on image load | P7 Hierarchy / CLS | Visual instability |
|
||
|
||
### API
|
||
| Anti-Pattern | Breaches | Why |
|
||
|--------------|----------|-----|
|
||
| `/getUsers` (verb in URL) | P2 Clarity | Resources are nouns |
|
||
| 200 with an error body | P9 Error Transparency | Status code lies |
|
||
| 500 with a stack trace | P8 Security, P9 | Information leak |
|
||
| No `Idempotency-Key` on a POST | P6 Idempotency | Retry is unsafe |
|
||
| 10MB response by default | P7 Performance | Unbounded payload |
|
||
|
||
### Security
|
||
| Anti-Pattern | Breaches | Why |
|
||
|--------------|----------|-----|
|
||
| `eval()` of any string | P4, P5 | Code injection |
|
||
| Hardcoded API key in source | P9 Secret Hygiene | Committed secret |
|
||
| `catch (e) {}` (swallow) | P7, P8 | Silent failure, fail-open |
|
||
| `md5` for password hashing | P6 Crypto | Broken primitive |
|
||
| Open CORS `*` in production | P1, P10 | Zero trust violated |
|
||
| `chmod 777` | P2 Least Privilege | Maximum privilege |
|
||
| Logging the request body | P9 Secret Hygiene | Token leak |
|
||
|
||
### Data
|
||
| Anti-Pattern | Breaches | Why |
|
||
|--------------|----------|-----|
|
||
| `VARCHAR` for a UUID | P7 Type Fidelity | Wrong type |
|
||
| No FOREIGN KEY | P3, P9 | Unenforced relationship |
|
||
| `FLOAT` for money | P7, P1 | Floating point error |
|
||
| `is_deleted` without filtering | P8 Lifecycle | Soft-delete leak |
|
||
| `SELECT *` | P10 Performance | Unbounded columns |
|
||
|
||
### Testing
|
||
| Anti-Pattern | Breaches | Why |
|
||
|--------------|----------|-----|
|
||
| Test that cannot fail | P10 No Test Theater | Not a test |
|
||
| `Date.now()` in a fixture | P3 Determinism | Flaky |
|
||
| Shared fixture mutated across tests | P2 Independence | Order-dependent |
|
||
| 500 e2e tests, 50 unit | P4 Fast Feedback | Inverted pyramid |
|
||
| `name: "test"` fixture | P7 Realism | Hides bugs |
|
||
|
||
### Performance
|
||
| Anti-Pattern | Breaches | Why |
|
||
|--------------|----------|-----|
|
||
| N+1 query in a loop | P3 Complexity | O(N) queries |
|
||
| No timeout on HTTP call | P4, P8 (concurrency) | Hang forever |
|
||
| Cache with no invalidation | P5 Caching | Stale forever |
|
||
| Unbounded in-memory sort | P4 Resource Bounds | OOM |
|
||
| Optimization without measurement | P1 Measure First | Guesswork |
|
||
|
||
### Observability
|
||
| Anti-Pattern | Breaches | Why |
|
||
|--------------|----------|-----|
|
||
| `console.log("here")` | P1 Structured | Not queryable |
|
||
| `user_id` as a metric label | P4 Cardinality | Unbounded bill |
|
||
| Average latency only | P8 SLO | Hides the tail |
|
||
| No `trace_id` propagation | P2 Correlation | Cannot trace |
|
||
| Logs without `request_id` | P3 Context | No correlation |
|
||
|
||
### Errors
|
||
| Anti-Pattern | Breaches | Why |
|
||
|--------------|----------|-----|
|
||
| `catch (e) { return null }` | P2 Fail Loudly | Silent failure |
|
||
| `throw new Error("error")` | P3 Fail Specifically | Generic |
|
||
| `return null` for "not found" | P1 Errors are Data | Conflates absence with error |
|
||
| Retry without backoff | P5, P8 | Retry storm |
|
||
| `throw` in a recovery path | P6 | Fail fast in wrong place |
|
||
|
||
### Documentation
|
||
| Anti-Pattern | Breaches | Why |
|
||
|--------------|----------|-----|
|
||
| Doc with no examples | P3 Examples | Incomplete |
|
||
| Stale doc (wrong, not updated) | P4 Currency | Worse than no doc |
|
||
| Unlisted doc (not in MANIFEST) | (framework rule) | Not part of framework |
|
||
| No audience statement | P2 Audience | Who is this for? |
|
||
|
||
### Concurrency
|
||
| Anti-Pattern | Breaches | Why |
|
||
|--------------|----------|-----|
|
||
| Shared mutable state, no lock | P1 Immutability | Race condition |
|
||
| Unbounded queue | P9 Bounded Queues | OOM |
|
||
| `channel.send()` with no timeout | P8 Timeout | Hang |
|
||
| Mutex held across I/O | P3 Lock Scope | Lock too long |
|
||
| Spawned work with no cancellation | P7 Cancellation | Orphaned work |
|
||
|
||
### DevOps
|
||
| Anti-Pattern | Breaches | Why |
|
||
|--------------|----------|-----|
|
||
| Manual deploy script | P2 Automation | Not repeatable |
|
||
| No rollback path | P4 Rollback | Irreversible deploy |
|
||
| Big-bang deploy | P5 Progressive | All-or-nothing |
|
||
| Rebuild per environment | P7 Immutability | Different artifacts |
|
||
| Snowflake server | P1, P6 | Not reproducible |
|
||
|
||
### Infrastructure as Code
|
||
| Anti-Pattern | Breaches | Why |
|
||
|--------------|----------|-----|
|
||
| Unpinned provider (`source` without `version`) | P5 Version Everything | Unversioned drift |
|
||
| `terraform apply` without a read `plan` | P4 Plan Before Apply | Unreviewed mutation |
|
||
| Local state in a shared environment | P8 Remote State with Locking | No lock = corruption |
|
||
| Hardcoded secret in HCL | P10 Secrets Never in Code | Committed secret |
|
||
| Copy-pasted block instead of a module | P6 Modules Compose | Bug duplicated |
|
||
| Manual change to a managed resource | P9 Drift is Recoverable | Unreconciled drift |
|
||
| Admin credentials in CI | P7 Least Privilege Providers | Overbroad grant |
|
||
| Committed `terraform.tfstate` | P3 State is Truth, P10 | Secret-bearing artifact in repo |
|
||
|
||
### Kubernetes
|
||
| Anti-Pattern | Breaches | Why |
|
||
|--------------|----------|-----|
|
||
| Bare pod (no controller) | P2 Pods are Mortal | No recovery/scale |
|
||
| No resource requests in prod | P4 Requests and Limits | BestEffort, first evicted |
|
||
| Liveness probe checks a dependency | P5 Probes Drive Health | Cascade restart |
|
||
| `cluster-admin` bound to a workload | P7 RBAC by Intent | Overbroad grant |
|
||
| `:latest` image tag in prod | P5 Version Everything | Unversioned drift |
|
||
| `emptyDir` for data that must persist | P8 Storage is Explicit | Data lost on pod death |
|
||
| Secrets baked into the image | P9 Config and Secrets Separate | No rotation without rebuild |
|
||
| `default` namespace in prod | P6 Namespaces Bound Blast Radius | No blast boundary |
|
||
| Shared PVC across StatefulSet replicas | P8 Storage is Explicit | Concurrent write corruption |
|
||
| `Delete` reclaim policy on prod storage | P8, P5 Reversibility | PVC delete = data delete |
|
||
|
||
## Cross-Cutting Anti-Patterns
|
||
|
||
| Anti-Pattern | Breaches | Why |
|
||
|--------------|----------|-----|
|
||
| "I'll add tests later" | C1 (no proof of correctness) | Later never comes |
|
||
| "It's just a prototype" | C5 (irreversible by default) | Prototypes go to prod |
|
||
| Copy-paste code | C6 (no composition) | Bug duplicated |
|
||
| God object | C3, C6 | One thing, many things |
|
||
| Leaky abstraction | C6, C2 | Hidden coupling |
|
||
|
||
## v0.2 Chaos Anti-Patterns (from IDEATE-13, IDEATE-14)
|
||
|
||
| Anti-Pattern | Breaches | Why |
|
||
|--------------|----------|-----|
|
||
| Orphaned P-rule (a domain principle with no matrix row) | matrix completeness, C6 | Breaks the conflict-resolution arbiter; the rule has no core trace |
|
||
| Deployable example artifact (standalone `.tf`/`.yaml` under `examples/`) | PROJECT.md "no runtime code", D-025 | Violates the docs-only contract; examples must be `.md` with fenced code |
|
||
| Unlisted v0.2 doc (new doc not added to MANIFEST) | manifest rule | Not part of the framework by definition |
|
||
|
||
## v0.3 Chaos Anti-Patterns (from IDEATE-20, IDEATE-24, IDEATE-25, IDEATE-27)
|
||
|
||
These are named, cross-cutting violations specific to the v0.3 domains. Reject on sight.
|
||
|
||
| Anti-Pattern | Breaches | Why |
|
||
|--------------|----------|-----|
|
||
| GitOps push-pattern (external CI pushes manifests to the cluster instead of an in-cluster agent pulling from git) | gitops P3 Pull, Don't Push; C1, C4 | Inverts the source-of-truth flow; requires push credentials into the cluster; breaks the reconciliation model (IDEATE-24, D-042) |
|
||
| i18n LTR-only assumption (layout assumes left-to-right; no `dir` attribute, physical CSS properties only) | i18n P6 Text Direction is a Layout Primitive; C1, C4 | Disqualifying for RTL/Bidi users; locale-correctness violation (IDEATE-25, D-043) |
|
||
| AI/ML orphan-model (a deployed prediction endpoint whose model has no lineage trace — no record of training run, dataset, or version) | ai-ml P3 Lineage is Traceable End-to-End; C7, C1 | Unreviewable, unrollbackable; the model is an unattributed artifact (IDEATE-27, D-045) |
|
||
| Compliance mutable audit log (audit records can be edited or deleted by an operator) | compliance P1 Audit Logs are Append-Only; C1, C5 | Destroys the audit trail; the audit log's value is immutability — mutation is itself an incident |
|
||
|
||
### v0.3 Deployable Artifact Types (IDEATE-20, D-020)
|
||
|
||
The following standalone file types are forbidden under `examples/` and elsewhere in the framework. Examples are `.md` files with fenced code only.
|
||
|
||
| Forbidden standalone artifact | Belongs in | Why |
|
||
|-------------------------------|-----------|-----|
|
||
| `.po` / `.pot` resource files | fenced code in `examples/good/`/`examples/bad/*.md` | Runtime localization artifact; violates docs-only contract |
|
||
| `.rego` / `.cedar` / `.sentinel` policy files | fenced code in `examples/*.md` | Runtime policy artifact; violates docs-only contract |
|
||
| Model artifacts (`.pkl`, `.onnx`, `.pt`, `.h5`, `.safetensors`) | fenced code + prose in `examples/*.md` | Runtime model artifact; violates docs-only contract |
|
||
| Signed manifests as standalone files (`.sig`, `.att`, `.intoto.jsonl`) | fenced code in `examples/*.md` | Runtime attestation artifact; violates docs-only contract |
|
||
| Standalone `.yaml` / `.tf` / `.sh` | fenced code in `examples/*.md` | (Carried forward from v0.2) Runtime deployable artifact |
|
||
|
||
## v0.3 Domain-Specific Anti-Patterns
|
||
|
||
### GitOps + Operators
|
||
|
||
| Anti-Pattern | Breaches | Why |
|
||
|--------------|----------|-----|
|
||
| Push-based deploy (external CI `kubectl apply` into the cluster) | P3 Pull, Don't Push | Inverts the model; requires push credentials; bypasses reconciliation |
|
||
| Manual `kubectl apply`/`kubectl edit` on a GitOps-managed resource | P8 Reconcile, Don't Mutate by Hand | Unreconciled drift; the next loop overwrites it — silent and unattributed |
|
||
| `cluster-admin` GitOps robot (controller bound to cluster-admin) | P10 Least Privilege Reconciliation | Overbroad grant; blast radius = entire cluster |
|
||
| No sync-failure notification (silent drift on health degradation) | P9 Failure is Observable and Surfaced | Silent drift is the bug the loop was supposed to surface |
|
||
|
||
### AI / ML
|
||
|
||
| Anti-Pattern | Breaches | Why |
|
||
|--------------|----------|-----|
|
||
| Unreproducible training run (unpinned data, code, config, or environment) | P1 Reproducibility is the First Class | Unreviewable; cannot debug, cannot rollback |
|
||
| "Use the latest model" (serving points at `model:latest` instead of a pinned version) | P5 Models are Versioned Artifacts | Unversioned drift; rollback undefined |
|
||
| Notebook in production (training/serving flow is a Jupyter notebook) | P9 Pipelines Compose, Notebooks Don't | No contracts, no composition, no reproducibility |
|
||
| Orphan model (deployed prediction with no lineage trace) | P3 Lineage is Traceable End-to-End | Unattributed artifact; cannot trace to data/code (IDEATE-27) |
|
||
|
||
### i18n
|
||
|
||
| Anti-Pattern | Breaches | Why |
|
||
|--------------|----------|-----|
|
||
| Inline string concatenation (`"Hello, " + name + "!"` in code) | P3 Resources are External, Not Inline | Not extractable; breaks translations; word-order differs per locale |
|
||
| `if (n == 1)` plural branching (hand-rolled plural logic) | P4 Plural and Gender are Parameterized | Wrong for Arabic, Russian, Polish; ICU MessageFormat handles plurals |
|
||
| LTR-only layout (no `dir` attribute, physical CSS `left`/`right`) | P6 Text Direction is a Layout Primitive | Disqualifying for RTL/Bidi (IDEATE-25) |
|
||
| Hand-rolled date/number formatter (`new Date().toString()`, manual string formatting) | P5 Formatting is Locale-Aware | Locale-incorrect; ignores ICU/CLDR |
|
||
|
||
### Compliance
|
||
|
||
| Anti-Pattern | Breaches | Why |
|
||
|--------------|----------|-----|
|
||
| Mutable audit log (operator can `UPDATE`/`DELETE` audit records) | P1 Audit Logs are Append-Only | Destroys the audit trail; mutation is itself an incident |
|
||
| Shared/generic identity in audit (`admin` or `system` as the actor for all actions) | P7 Identity is Attributable | No attribution; no accountability; cannot investigate |
|
||
| Secret leaked in audit log (request body or token captured in an audit event) | P9 Secrets and Sensitive Data are Redacted in Audit | Audit log becomes a secret exfiltration channel |
|
||
| Manual evidence assembly at audit time (scramble to collect logs/scans/attestations on demand) | P6 Evidence is Collected Continuously | Audit-unready; evidence gathered under pressure is incomplete and unreliable | |