@causyne/agent 0.0.0-stage → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (274) hide show
  1. package/LICENSE +102 -0
  2. package/README.md +31 -2
  3. package/SECURITY.md +24 -0
  4. package/bin/causyne.js +13 -0
  5. package/docs/ARCHITECTURE.md +63 -0
  6. package/docs/PROVENANCE.md +29 -0
  7. package/docs/SECURITY_REVIEW.md +89 -0
  8. package/docs/THIRD_PARTY_NOTICES.md +49 -0
  9. package/native-skills/ai-engineering/context-window-management/SKILL.md +43 -0
  10. package/native-skills/ai-engineering/llm-evaluation/SKILL.md +46 -0
  11. package/native-skills/ai-engineering/model-cost-and-latency/SKILL.md +46 -0
  12. package/native-skills/ai-engineering/prompt-construction/SKILL.md +42 -0
  13. package/native-skills/ai-engineering/retrieval-augmented-generation/SKILL.md +42 -0
  14. package/native-skills/ai-engineering/structured-output-and-schemas/SKILL.md +45 -0
  15. package/native-skills/ai-engineering/tool-calling-agents/SKILL.md +43 -0
  16. package/native-skills/android/app-performance-profiling/SKILL.md +42 -0
  17. package/native-skills/android/background-work-scheduling/SKILL.md +47 -0
  18. package/native-skills/android/compose-state-and-recomposition/SKILL.md +43 -0
  19. package/native-skills/android/gradle-build-configuration/SKILL.md +41 -0
  20. package/native-skills/android/lifecycle-and-leaks/SKILL.md +46 -0
  21. package/native-skills/android/play-store-release/SKILL.md +43 -0
  22. package/native-skills/android/room-and-persistence/SKILL.md +40 -0
  23. package/native-skills/backend/authentication-and-sessions/SKILL.md +45 -0
  24. package/native-skills/backend/background-jobs-and-queues/SKILL.md +42 -0
  25. package/native-skills/backend/caching-strategy/SKILL.md +44 -0
  26. package/native-skills/backend/graceful-shutdown/SKILL.md +42 -0
  27. package/native-skills/backend/rate-limiting-and-quotas/SKILL.md +40 -0
  28. package/native-skills/backend/rest-api-design/SKILL.md +40 -0
  29. package/native-skills/backend/webhook-delivery-and-receipt/SKILL.md +43 -0
  30. package/native-skills/cloud/cost-optimisation/SKILL.md +46 -0
  31. package/native-skills/cloud/iam-least-privilege/SKILL.md +43 -0
  32. package/native-skills/cloud/infrastructure-as-code/SKILL.md +43 -0
  33. package/native-skills/cloud/multi-region-and-failover/SKILL.md +43 -0
  34. package/native-skills/cloud/serverless-patterns/SKILL.md +47 -0
  35. package/native-skills/data/data-quality-monitoring/SKILL.md +51 -0
  36. package/native-skills/data/etl-pipeline-reliability/SKILL.md +43 -0
  37. package/native-skills/data/exploratory-analysis/SKILL.md +43 -0
  38. package/native-skills/data/metric-definition/SKILL.md +42 -0
  39. package/native-skills/data/notebook-to-production/SKILL.md +43 -0
  40. package/native-skills/database/backup-and-recovery/SKILL.md +43 -0
  41. package/native-skills/database/connection-pooling/SKILL.md +42 -0
  42. package/native-skills/database/data-integrity-and-constraints/SKILL.md +42 -0
  43. package/native-skills/database/query-optimisation/SKILL.md +38 -0
  44. package/native-skills/database/safe-migrations/SKILL.md +47 -0
  45. package/native-skills/database/schema-design/SKILL.md +38 -0
  46. package/native-skills/database/transactions-and-isolation/SKILL.md +41 -0
  47. package/native-skills/design/colour-system-construction/SKILL.md +38 -0
  48. package/native-skills/design/design-direction-brief/SKILL.md +41 -0
  49. package/native-skills/design/motion-and-transitions/SKILL.md +38 -0
  50. package/native-skills/design/responsive-strategy/SKILL.md +39 -0
  51. package/native-skills/design/spacing-and-rhythm/SKILL.md +38 -0
  52. package/native-skills/design/type-scale-and-hierarchy/SKILL.md +39 -0
  53. package/native-skills/design/visual-qa-loop/SKILL.md +42 -0
  54. package/native-skills/devops/docker-multi-stage-builds/SKILL.md +60 -0
  55. package/native-skills/devops/github-actions-ci/SKILL.md +60 -0
  56. package/native-skills/devops/incident-triage/SKILL.md +38 -0
  57. package/native-skills/devops/kubernetes-deployment-hardening/SKILL.md +64 -0
  58. package/native-skills/devops/observability-baseline/SKILL.md +38 -0
  59. package/native-skills/devops/secret-management/SKILL.md +40 -0
  60. package/native-skills/devops/terraform-state-and-modules/SKILL.md +36 -0
  61. package/native-skills/devops/zero-downtime-deploys/SKILL.md +40 -0
  62. package/native-skills/git/bisect-regression-hunt/SKILL.md +43 -0
  63. package/native-skills/git/branch-strategy/SKILL.md +39 -0
  64. package/native-skills/git/commit-hygiene/SKILL.md +41 -0
  65. package/native-skills/git/history-recovery/SKILL.md +44 -0
  66. package/native-skills/git/large-repository-surgery/SKILL.md +46 -0
  67. package/native-skills/git/merge-conflict-resolution/SKILL.md +42 -0
  68. package/native-skills/media/cinematic-3d-shot/SKILL.md +104 -0
  69. package/native-skills/mobile/app-startup-optimisation/SKILL.md +41 -0
  70. package/native-skills/mobile/cross-platform-tradeoffs/SKILL.md +42 -0
  71. package/native-skills/mobile/deep-linking/SKILL.md +39 -0
  72. package/native-skills/mobile/mobile-storage-security/SKILL.md +45 -0
  73. package/native-skills/mobile/offline-first-sync/SKILL.md +42 -0
  74. package/native-skills/mobile/push-notifications/SKILL.md +38 -0
  75. package/native-skills/performance/algorithmic-complexity/SKILL.md +43 -0
  76. package/native-skills/performance/concurrency-and-parallelism/SKILL.md +42 -0
  77. package/native-skills/performance/load-testing/SKILL.md +42 -0
  78. package/native-skills/performance/memory-and-leak-hunting/SKILL.md +41 -0
  79. package/native-skills/performance/network-and-payload-efficiency/SKILL.md +42 -0
  80. package/native-skills/performance/profiling-methodology/SKILL.md +46 -0
  81. package/native-skills/python/async-correctness/SKILL.md +40 -0
  82. package/native-skills/python/cli-tool-construction/SKILL.md +44 -0
  83. package/native-skills/python/data-processing-pipelines/SKILL.md +38 -0
  84. package/native-skills/python/environment-isolation/SKILL.md +41 -0
  85. package/native-skills/python/packaging-and-distribution/SKILL.md +56 -0
  86. package/native-skills/python/pytest-suite-design/SKILL.md +39 -0
  87. package/native-skills/python/type-hints-and-static-checking/SKILL.md +42 -0
  88. package/native-skills/security/authorization-model/SKILL.md +42 -0
  89. package/native-skills/security/crypto-usage/SKILL.md +48 -0
  90. package/native-skills/security/dependency-supply-chain/SKILL.md +42 -0
  91. package/native-skills/security/input-validation-and-injection/SKILL.md +44 -0
  92. package/native-skills/security/secure-file-uploads/SKILL.md +46 -0
  93. package/native-skills/security/security-headers-and-csp/SKILL.md +44 -0
  94. package/native-skills/security/threat-modelling/SKILL.md +46 -0
  95. package/native-skills/testing/end-to-end-test-stability/SKILL.md +42 -0
  96. package/native-skills/testing/property-based-testing/SKILL.md +46 -0
  97. package/native-skills/testing/regression-test-from-a-bug/SKILL.md +41 -0
  98. package/native-skills/testing/snapshot-and-visual-regression/SKILL.md +42 -0
  99. package/native-skills/testing/test-doubles-and-mocking/SKILL.md +43 -0
  100. package/native-skills/testing/test-strategy-and-pyramid/SKILL.md +39 -0
  101. package/native-skills/testing/writing-good-assertions/SKILL.md +42 -0
  102. package/native-skills/web/accessible-components/SKILL.md +45 -0
  103. package/native-skills/web/api-client-resilience/SKILL.md +39 -0
  104. package/native-skills/web/bundle-size-reduction/SKILL.md +38 -0
  105. package/native-skills/web/core-web-vitals/SKILL.md +40 -0
  106. package/native-skills/web/css-layout-systems/SKILL.md +41 -0
  107. package/native-skills/web/form-validation-ux/SKILL.md +39 -0
  108. package/native-skills/web/react-state-architecture/SKILL.md +41 -0
  109. package/native-skills/web/ssr-hydration-correctness/SKILL.md +45 -0
  110. package/package.json +68 -4
  111. package/src/agentLoop.js +2458 -0
  112. package/src/appChannel.js +109 -0
  113. package/src/approvalGrants.js +66 -0
  114. package/src/auditLog.js +52 -0
  115. package/src/autoUpdate.js +12 -0
  116. package/src/capabilities.js +36 -0
  117. package/src/checkpoints.js +1199 -0
  118. package/src/cliMode.js +638 -0
  119. package/src/commands.js +805 -0
  120. package/src/compiledSkills.js +540 -0
  121. package/src/config.js +130 -0
  122. package/src/contextManager.js +498 -0
  123. package/src/cortex/autoCondenser.js +192 -0
  124. package/src/cortex/provisioner.js +27 -0
  125. package/src/cortex/vectorDb.js +447 -0
  126. package/src/designPalettes.js +99 -0
  127. package/src/devMode.js +6 -0
  128. package/src/embodimentSession.js +180 -0
  129. package/src/entrypoint.js +194 -0
  130. package/src/execSafe.js +21 -0
  131. package/src/gitSnapshot.js +378 -0
  132. package/src/mcp/jsonRpc.js +165 -0
  133. package/src/mcp/mcpClient.js +136 -0
  134. package/src/mcp/mcpRegistry.js +207 -0
  135. package/src/memory.js +62 -0
  136. package/src/memoryManager.js +124 -0
  137. package/src/modelCatalogue.js +132 -0
  138. package/src/modelIds.js +42 -0
  139. package/src/modelRouter.js +145 -0
  140. package/src/outputStore.js +246 -0
  141. package/src/perception.js +124 -0
  142. package/src/planCache.js +437 -0
  143. package/src/procSignal.js +32 -0
  144. package/src/providers/anthropic.js +408 -0
  145. package/src/providers/base.js +328 -0
  146. package/src/providers/dashscope-byok.js +86 -0
  147. package/src/providers/deepseek.js +80 -0
  148. package/src/providers/factory.js +37 -0
  149. package/src/providers/gemini.js +346 -0
  150. package/src/providers/moonshot.js +73 -0
  151. package/src/providers/muse.js +169 -0
  152. package/src/providers/ollama.js +104 -0
  153. package/src/providers/openai-compatible.js +84 -0
  154. package/src/providers/openai.js +20 -0
  155. package/src/providers/qwen-byok.js +76 -0
  156. package/src/providers/xai.js +73 -0
  157. package/src/provisioning/capabilityConsent.js +24 -0
  158. package/src/provisioning/capabilityProvisioner.js +271 -0
  159. package/src/provisioning/capabilityTools.js +29 -0
  160. package/src/reporting.js +373 -0
  161. package/src/sandbox.js +529 -0
  162. package/src/sessionStore.js +279 -0
  163. package/src/skillsManager.js +288 -0
  164. package/src/slopDetector.js +307 -0
  165. package/src/taskBuffer.js +45 -0
  166. package/src/taskShape.js +241 -0
  167. package/src/textDiff.js +150 -0
  168. package/src/tokenTracker.js +560 -0
  169. package/src/tool-scripts/ax_snapshot.applescript +39 -0
  170. package/src/tool-scripts/ax_snapshot.ps1 +10 -0
  171. package/src/tool-scripts/desktop_act.applescript +58 -0
  172. package/src/tool-scripts/resolve_automator.py +119 -0
  173. package/src/toolPacks.js +524 -0
  174. package/src/tools/archive.js +63 -0
  175. package/src/tools/astryxOracle.js +78 -0
  176. package/src/tools/axSnapshot.js +165 -0
  177. package/src/tools/blenderAutomator.js +349 -0
  178. package/src/tools/browserAutomator.js +252 -0
  179. package/src/tools/checkSystemSpecs.js +64 -0
  180. package/src/tools/clipboard.js +36 -0
  181. package/src/tools/codeSearchAst.js +101 -0
  182. package/src/tools/codeSearcher.js +230 -0
  183. package/src/tools/codeTools.js +262 -0
  184. package/src/tools/codebaseSearch.js +75 -0
  185. package/src/tools/createSkill.js +129 -0
  186. package/src/tools/deferredMcpSearch.js +246 -0
  187. package/src/tools/desktopAct.js +208 -0
  188. package/src/tools/desktopOpen.js +34 -0
  189. package/src/tools/dynamicLoader.js +44 -0
  190. package/src/tools/executeProceduralMedia.js +93 -0
  191. package/src/tools/fsDelete.js +51 -0
  192. package/src/tools/fsEdit.js +105 -0
  193. package/src/tools/fsFind.js +128 -0
  194. package/src/tools/fsList.js +77 -0
  195. package/src/tools/fsMove.js +57 -0
  196. package/src/tools/fsRead.js +87 -0
  197. package/src/tools/fsSearch.js +198 -0
  198. package/src/tools/fsWrite.js +41 -0
  199. package/src/tools/gameAiBehaviorTree.js +208 -0
  200. package/src/tools/gameAnimationRig.js +194 -0
  201. package/src/tools/gameAssetFetcher.js +372 -0
  202. package/src/tools/gameAssetHarvester.js +210 -0
  203. package/src/tools/gameAudioSynth.js +267 -0
  204. package/src/tools/gameBuilder.js +886 -0
  205. package/src/tools/gameCanvasAudit.js +101 -0
  206. package/src/tools/gameCinematicSequencer.js +151 -0
  207. package/src/tools/gameDataForge.js +124 -0
  208. package/src/tools/gameDialogueTreeGen.js +166 -0
  209. package/src/tools/gameEconomyBalancer.js +161 -0
  210. package/src/tools/gameEntitySpawner.js +207 -0
  211. package/src/tools/gameLoreForge.js +153 -0
  212. package/src/tools/gameQuestArcBuilder.js +152 -0
  213. package/src/tools/gameSceneBuilder.js +158 -0
  214. package/src/tools/gameShaderForge.js +181 -0
  215. package/src/tools/gameTilemapGenerator.js +164 -0
  216. package/src/tools/gameUiHudBuilder.js +292 -0
  217. package/src/tools/gameVfxEmitterGen.js +108 -0
  218. package/src/tools/gameWebRuntimeInspector.js +91 -0
  219. package/src/tools/generateMediaViaApi.js +358 -0
  220. package/src/tools/gitExec.js +54 -0
  221. package/src/tools/godotAutomator.js +437 -0
  222. package/src/tools/manageLocalAiDependencies.js +220 -0
  223. package/src/tools/memoryWrite.js +99 -0
  224. package/src/tools/multiEdit.js +107 -0
  225. package/src/tools/palmierAutomator.js +104 -0
  226. package/src/tools/pdfReader.js +112 -0
  227. package/src/tools/persistentShell.js +148 -0
  228. package/src/tools/printer.js +316 -0
  229. package/src/tools/procTerm.js +91 -0
  230. package/src/tools/processList.js +52 -0
  231. package/src/tools/readNativeSkill.js +39 -0
  232. package/src/tools/registry.js +277 -0
  233. package/src/tools/resolveAutomator.js +102 -0
  234. package/src/tools/screenshot.js +75 -0
  235. package/src/tools/subagentOrchestrator.js +305 -0
  236. package/src/tools/sysRun.js +125 -0
  237. package/src/tools/todoWrite.js +75 -0
  238. package/src/tools/toolDispatch.js +127 -0
  239. package/src/tools/toolForge.js +124 -0
  240. package/src/tools/updatePlan.js +88 -0
  241. package/src/tools/viewImage.js +82 -0
  242. package/src/tools/visionInspector.js +154 -0
  243. package/src/tools/webFetch.js +74 -0
  244. package/src/tools/webSearch.js +82 -0
  245. package/src/tui/ask.js +164 -0
  246. package/src/tui/banner.js +158 -0
  247. package/src/tui/block.js +152 -0
  248. package/src/tui/chatRenderer.js +953 -0
  249. package/src/tui/completion.js +424 -0
  250. package/src/tui/dialogs.js +606 -0
  251. package/src/tui/diff.js +296 -0
  252. package/src/tui/history.js +135 -0
  253. package/src/tui/home.js +217 -0
  254. package/src/tui/invocation.js +105 -0
  255. package/src/tui/keys.js +443 -0
  256. package/src/tui/lineEditor.js +256 -0
  257. package/src/tui/overlay.js +256 -0
  258. package/src/tui/prompt.js +1258 -0
  259. package/src/tui/selectList.js +335 -0
  260. package/src/tui/stage.js +330 -0
  261. package/src/tui/stageSurface.js +609 -0
  262. package/src/tui/statusLine.js +254 -0
  263. package/src/tui/text.js +345 -0
  264. package/src/tui/theme.js +393 -0
  265. package/src/tui/toolDisplay.js +176 -0
  266. package/src/tui/transcript.js +235 -0
  267. package/src/tui/viewport.js +337 -0
  268. package/src/uncertainty.js +271 -0
  269. package/src/userSkills.js +265 -0
  270. package/src/utils/cli_ui.js +0 -0
  271. package/src/utils/inquirer.js +12 -0
  272. package/src/utils/paths.js +37 -0
  273. package/src/version.js +38 -0
  274. package/src/vfeTracker.js +220 -0
@@ -0,0 +1,40 @@
1
+ ---
2
+ name: rest-api-design
3
+ description: Design or review an HTTP API. Use when endpoints are being added, when responses are inconsistent, or when clients need to special-case error handling.
4
+ ---
5
+
6
+ # REST API Design
7
+
8
+ ## Workflow
9
+
10
+ 1. Model resources, not actions.
11
+ - `POST /orders`, not `POST /createOrder`. The verb is the method. When an operation genuinely is not a resource change (`/search`, `/reindex`), say so explicitly rather than contorting a noun.
12
+ - **Done when:** every path is a noun and every method carries the verb.
13
+
14
+ 2. Use status codes the way clients expect.
15
+ - 200 with a body, 201 with a `Location`, 204 with none. 400 malformed, 401 unauthenticated, 403 authenticated but not permitted, 404 absent, 409 conflict, 422 semantically invalid, 429 rate-limited.
16
+ - Never return 200 with an error inside the body. Every client's error handling depends on the status.
17
+ - **Done when:** no successful-looking status carries an error payload.
18
+
19
+ 3. Give errors one shape.
20
+ - A stable machine-readable code, a human message, and a field-level detail list where relevant. RFC 9457 problem details is a reasonable default.
21
+ - Never leak a stack trace or an internal identifier to a client.
22
+ - **Done when:** every error response validates against one schema.
23
+
24
+ 4. Paginate every collection from day one.
25
+ - Cursor-based, not offset-based: offset pagination skips and repeats rows when the underlying data changes between pages. An unpaginated list endpoint is an outage waiting for the table to grow.
26
+ - **Done when:** every collection endpoint has a documented limit and cursor.
27
+
28
+ 5. Version before you need to.
29
+ - A path prefix (`/v1/`) is the simplest thing that works. Adding a version after clients exist is far harder than starting with one.
30
+ - **Done when:** every route carries a version.
31
+
32
+ 6. Make writes idempotent.
33
+ - PUT and DELETE are idempotent by definition. POST needs an `Idempotency-Key` header if a retry must not duplicate the effect — and clients on flaky networks WILL retry.
34
+ - **Done when:** replaying a write with the same key produces one effect.
35
+
36
+ ## Verification
37
+
38
+ - An OpenAPI document describes every route and matches the implementation.
39
+ - Every error path returns the shared error shape with the correct status.
40
+ - Replaying a POST with the same idempotency key creates one record.
@@ -0,0 +1,43 @@
1
+ ---
2
+ name: webhook-delivery-and-receipt
3
+ description: Send or receive webhooks. Use when integrating a third-party callback, when webhook handlers time out, or when duplicate deliveries cause duplicate effects.
4
+ ---
5
+
6
+ # Webhook Delivery and Receipt
7
+
8
+ ## Receiving
9
+
10
+ 1. **Verify the signature before parsing.**
11
+ - Compute the expected signature over the RAW body and compare in constant time. Parsing first means acting on unverified input, and many frameworks mutate the body during parsing so the signature can no longer be checked at all.
12
+ - **Done when:** an unsigned or wrongly signed request is rejected with 401 before any parsing.
13
+
14
+ 2. **Check the timestamp.**
15
+ - Reject anything older than a few minutes. Without this, a captured request can be replayed indefinitely.
16
+ - **Done when:** a replayed old request is rejected.
17
+
18
+ 3. **Acknowledge fast, process later.**
19
+ - Persist the event and return 200 within a couple of seconds; do the work in a job. Senders time out quickly and retry, and a slow handler turns one event into many.
20
+ - **Done when:** the handler returns before doing any real work.
21
+
22
+ 4. **Deduplicate on the event id.**
23
+ - Delivery is at-least-once from every provider. Store the id with a uniqueness constraint and ignore repeats.
24
+ - **Done when:** delivering the same event twice produces one effect.
25
+
26
+ 5. **Return the right status.**
27
+ - 200 for accepted, including for a duplicate. 4xx only for something a retry cannot fix — a 4xx usually makes the sender stop permanently. 5xx to ask for a retry.
28
+ - **Done when:** the status semantics are documented per branch.
29
+
30
+ ## Sending
31
+
32
+ 1. **Sign every request** over the raw body with a shared secret and include a timestamp.
33
+ 2. **Retry with exponential backoff and jitter**, for hours, then dead-letter and notify.
34
+ 3. **Give each event a stable id** so the receiver can deduplicate.
35
+ 4. **Time out fast** — a few seconds — so one slow receiver cannot block the queue.
36
+ - **Done when:** a receiver that never responds does not degrade delivery to others.
37
+
38
+ ## Verification
39
+
40
+ - An unsigned request is rejected.
41
+ - The same event delivered twice produces one effect.
42
+ - The handler responds in under two seconds under load.
43
+ - A failing receiver ends up in the dead-letter queue with an alert.
@@ -0,0 +1,46 @@
1
+ ---
2
+ name: cost-optimisation
3
+ description: Reduce cloud spend. Use when a bill grows unexpectedly, before scaling up, or during a cost review.
4
+ ---
5
+
6
+ # Cloud Cost Optimisation
7
+
8
+ ## Where the money usually is
9
+
10
+ Idle resources, oversized instances, data transfer, and storage nobody deleted. Rarely the thing people assume. Find out before acting.
11
+
12
+ ## Workflow
13
+
14
+ 1. Attribute the spend before changing anything.
15
+ - Tag everything by team, environment and service, then break the bill down. An unattributed bill cannot be reduced deliberately.
16
+ - **Done when:** most of the spend is attributed to a named owner.
17
+
18
+ 2. Delete what is not used.
19
+ - Unattached volumes, old snapshots, idle load balancers, unused addresses, forgotten environments. This is the largest and easiest win in most accounts and requires no architectural change.
20
+ - **Done when:** every unattached resource is deleted or justified.
21
+
22
+ 3. Right-size from measurement.
23
+ - Instances provisioned for a peak that never came. Look at actual utilisation over weeks and resize. Under 20% sustained is over-provisioned.
24
+ - **Done when:** every instance's size is justified by observed utilisation.
25
+
26
+ 4. Match the storage class to the access pattern.
27
+ - Data read once a year should not sit in the hot tier. Lifecycle rules move it automatically, and this is often a large saving on old logs and backups.
28
+ - **Done when:** every bucket has a lifecycle policy.
29
+
30
+ 5. Look hard at data transfer.
31
+ - Cross-zone and cross-region traffic is billed and frequently accidental — a service talking to a database in another zone, or a chatty pattern that should be batched. This line is often larger than compute and almost never examined.
32
+ - **Done when:** transfer charges are attributed to specific flows.
33
+
34
+ 6. Commit only to a proven baseline.
35
+ - Reserved capacity or savings plans for load you are certain persists. Committing to a spike locks in the wrong number for a year.
36
+ - **Done when:** commitments cover only the measured steady-state.
37
+
38
+ 7. Alert on the anomaly, not the total.
39
+ - A budget alert at month end is too late. Alert on a daily rate change.
40
+ - **Done when:** a sudden daily increase raises an alert within a day.
41
+
42
+ ## Verification
43
+
44
+ - Spend is attributed by owner.
45
+ - Before and after monthly figures are reported.
46
+ - Anomaly alerting is in place.
@@ -0,0 +1,43 @@
1
+ ---
2
+ name: iam-least-privilege
3
+ description: Configure cloud permissions or service accounts. Use when creating a role, when a policy grants broad access, or during a security review.
4
+ ---
5
+
6
+ # IAM Least Privilege
7
+
8
+ ## The default failure
9
+
10
+ A wildcard policy attached because something did not work and the error message did not say which permission was missing. It works, so it stays, and it is a full compromise waiting for one leaked credential.
11
+
12
+ ## Workflow
13
+
14
+ 1. Give every workload its own identity.
15
+ - Shared credentials make it impossible to tell what did something, and impossible to revoke one consumer without breaking the others.
16
+ - **Done when:** each workload has a distinct identity.
17
+
18
+ 2. Start from deny and add what fails.
19
+ - Run with no permissions, read the access-denied errors, and grant exactly those. This is slower than starting broad and narrowing, and it is the only approach that actually converges.
20
+ - **Done when:** the policy contains only permissions the workload demonstrably needs.
21
+
22
+ 3. Scope to resources, not just to actions.
23
+ - Read on one bucket, not read on all buckets. Most policies get the action right and leave the resource as a wildcard, which is most of the exposure.
24
+ - **Done when:** no resource field is a bare wildcard.
25
+
26
+ 4. Use short-lived credentials.
27
+ - Workload identity federation or the platform's instance identity. A long-lived key in an environment variable is a key in every backup, log and image.
28
+ - **Done when:** no static long-lived credential exists for any workload.
29
+
30
+ 5. Add conditions where they cost nothing.
31
+ - Source address range, requiring encryption in transit, or requiring multi-factor for sensitive actions. Each closes an avenue at no operational cost.
32
+ - **Done when:** high-value permissions carry a condition.
33
+
34
+ 6. Review with the analyser and remove unused grants.
35
+ - Cloud providers report permissions granted but never used. That report is the shortest path to a smaller blast radius.
36
+ - **Done when:** permissions unused for a stated period are removed.
37
+
38
+ ## Verification
39
+
40
+ - No policy contains a wildcard action on a wildcard resource.
41
+ - Each workload has its own identity with its own policy.
42
+ - No long-lived static credential exists.
43
+ - The access analyser reports no unused permission older than the review period.
@@ -0,0 +1,43 @@
1
+ ---
2
+ name: infrastructure-as-code
3
+ description: Manage cloud infrastructure through code. Use when resources were created by hand, when environments have drifted, or when setting up a new environment.
4
+ ---
5
+
6
+ # Infrastructure as Code
7
+
8
+ ## The rule
9
+
10
+ If it was created by hand, it does not exist reproducibly. A console change is invisible, unreviewable, and gone when the account is recreated. Every persistent resource is defined in code.
11
+
12
+ ## Workflow
13
+
14
+ 1. Import what already exists before writing anything new.
15
+ - Most environments have hand-made resources. Import them into state so the code describes reality; writing new code alongside undocumented resources creates conflicts and duplicates.
16
+ - **Done when:** a plan against the existing environment shows no changes.
17
+
18
+ 2. Make the environment a parameter.
19
+ - One module, several variable files. Copied directories per environment drift within weeks, and the drift is discovered during an incident.
20
+ - **Done when:** adding an environment requires only a new variables file.
21
+
22
+ 3. Separate state by blast radius.
23
+ - Networking, data stores and applications in separate states. One state file for everything means a mistake in the application layer can plan a change to the database.
24
+ - **Done when:** an application change cannot plan a change to a data store.
25
+
26
+ 4. Review the plan as code review.
27
+ - The plan output goes on the pull request. Reviewing the source without the plan misses what the provider will actually do — particularly the resources it intends to replace.
28
+ - **Done when:** every change is reviewed with its plan attached.
29
+
30
+ 5. Guard destructive changes.
31
+ - Deletion protection on data stores, and a lifecycle rule preventing accidental destruction. A resource replacement that recreates a database is the classic catastrophic apply.
32
+ - **Done when:** no plan can destroy a data store without an explicit override.
33
+
34
+ 6. Detect drift on a schedule.
35
+ - A periodic plan that reports differences. Someone will change something in the console; the question is whether you find out in a day or during an incident.
36
+ - **Done when:** a scheduled drift check reports differences to an owner.
37
+
38
+ ## Verification
39
+
40
+ - A plan against production shows no unexplained changes.
41
+ - A new environment can be created from code alone.
42
+ - Data stores are protected from accidental destruction.
43
+ - Drift detection runs on a schedule.
@@ -0,0 +1,43 @@
1
+ ---
2
+ name: multi-region-and-failover
3
+ description: Design for regional failure or high availability. Use when planning for an outage, when latency varies by geography, or when a single region is a single point of failure.
4
+ ---
5
+
6
+ # Multi-Region and Failover
7
+
8
+ ## Be honest about the cost
9
+
10
+ Multi-region multiplies infrastructure cost and operational complexity, and introduces data consistency problems that do not exist in one region. Most systems should first make one region genuinely resilient — multiple availability zones, tested backups, tested restore. Reach for multi-region when the requirement demands it, not by default.
11
+
12
+ ## Workflow
13
+
14
+ 1. State the requirement in numbers.
15
+ - How much data may be lost, how long recovery may take, and what an hour of downtime costs. These decide whether the complexity is justified.
16
+ - **Done when:** the recovery objectives and the cost of downtime are written down.
17
+
18
+ 2. Choose the posture deliberately.
19
+ - Backup and restore: cheapest, hours to recover. Warm standby: minutes, moderate cost. Active-active: seconds, highest cost and hardest consistency.
20
+ - **Done when:** the posture is chosen against the stated numbers.
21
+
22
+ 3. Solve the data problem first.
23
+ - This is the hard part, and everything else is easy by comparison. Asynchronous replication means a failover loses the replication lag. Synchronous costs latency on every write. Active-active means conflicts, and you must define the resolution rule.
24
+ - **Done when:** the replication mode and its data-loss window are stated.
25
+
26
+ 4. Make failover a routine, tested operation.
27
+ - Automate it, document it, and rehearse it on a schedule. An untested failover fails when it is needed — that is the observed pattern, not a caution.
28
+ - **Done when:** a failover has been performed in a rehearsal within the last quarter.
29
+
30
+ 5. Do not forget what is regional but invisible.
31
+ - Certificates, secrets, DNS records, container registries, queues, and scheduled jobs. Failover fails on the one dependency nobody listed.
32
+ - **Done when:** every regional dependency has a plan.
33
+
34
+ 6. Plan the failback.
35
+ - Returning to the primary region requires reconciling data written to the secondary. This is frequently harder than the failover and is usually not planned.
36
+ - **Done when:** failback has been rehearsed and its data reconciliation is defined.
37
+
38
+ ## Verification
39
+
40
+ - Recovery objectives are stated and the posture meets them.
41
+ - A failover rehearsal has been performed and timed.
42
+ - Every regional dependency is inventoried.
43
+ - Failback has been rehearsed.
@@ -0,0 +1,47 @@
1
+ ---
2
+ name: serverless-patterns
3
+ description: Build or fix serverless functions. Use when cold starts are slow, when a function times out, or when a function exhausts a downstream resource.
4
+ ---
5
+
6
+ # Serverless Patterns
7
+
8
+ ## What is different
9
+
10
+ The execution environment is created and destroyed outside your control, may be reused, and may run thousands of copies at once. Every problem specific to serverless comes from one of those three.
11
+
12
+ ## Workflow
13
+
14
+ 1. Move initialisation outside the handler.
15
+ - Code outside the handler runs once per environment and is reused across invocations. Clients, configuration and connection setup belong there. Inside the handler it runs on every single invocation.
16
+ - **Done when:** no client is constructed inside the handler.
17
+
18
+ 2. Never rely on local state persisting, and never assume it will not.
19
+ - A warm environment retains its filesystem and memory. Writing a temporary file and not cleaning it up will eventually fill the space; caching in memory works but must tolerate a cold start.
20
+ - **Done when:** the function is correct whether or not the environment is reused.
21
+
22
+ 3. Bound the concurrency to protect what is downstream.
23
+ - A thousand concurrent functions each opening a database connection will exhaust the database. Set a reserved concurrency limit, and use a connection proxy or a data API rather than direct connections.
24
+ - **Done when:** peak concurrency cannot exceed what downstream can serve.
25
+
26
+ 4. Make every handler idempotent.
27
+ - Event sources deliver at least once. A retry after a timeout means the work may already have happened.
28
+ - **Done when:** processing the same event twice produces one effect.
29
+
30
+ 5. Set timeouts deliberately, on both ends.
31
+ - The function timeout must exceed the sum of its outbound call timeouts, and each outbound call must have one. Otherwise the function times out with no useful log.
32
+ - **Done when:** every outbound call has a timeout shorter than the function's.
33
+
34
+ 6. Handle failure explicitly.
35
+ - A dead-letter target for every asynchronous invocation, and an alert on its depth. Without one, failures vanish.
36
+ - **Done when:** failed invocations land somewhere with an alert.
37
+
38
+ 7. Address cold starts only if measured.
39
+ - Smaller packages, a faster runtime, and provisioned concurrency where the latency genuinely matters. Provisioned concurrency costs money continuously — measure first.
40
+ - **Done when:** cold start latency is measured and the mitigation is justified.
41
+
42
+ ## Verification
43
+
44
+ - Clients are created once per environment, not per invocation.
45
+ - A load test does not exhaust downstream connections.
46
+ - The same event delivered twice produces one effect.
47
+ - Failed asynchronous invocations reach a dead-letter target.
@@ -0,0 +1,51 @@
1
+ ---
2
+ name: data-quality-monitoring
3
+ description: Detect data problems before people act on them. Use when bad data has reached a dashboard, or when setting up a new data source.
4
+ ---
5
+
6
+ # Data Quality Monitoring
7
+
8
+ ## The failure that costs most
9
+
10
+ Not the pipeline that breaks — that gets noticed. The pipeline that keeps running while the data quietly goes wrong. Those are discovered weeks later, after decisions have been made on the numbers.
11
+
12
+ ## The dimensions worth monitoring
13
+
14
+ - **Freshness** — is the newest record as recent as it should be.
15
+ - **Volume** — is the row count within its normal band.
16
+ - **Schema** — have columns or types changed upstream.
17
+ - **Distribution** — has a column's shape shifted beyond its normal variation.
18
+ - **Uniqueness and referential integrity** — are keys still unique, do references still resolve.
19
+
20
+ ## Workflow
21
+
22
+ 1. Baseline before alerting.
23
+ - Measure normal for a few weeks. Alerting on a guessed threshold produces noise, and a noisy alert is an ignored alert.
24
+ - **Done when:** each check has a threshold derived from observed variation.
25
+
26
+ 2. Check freshness first.
27
+ - It catches the most failures for the least effort. A stale partition means the pipeline is broken regardless of what else passes.
28
+ - **Done when:** every dataset has a maximum-age alert.
29
+
30
+ 3. Detect schema change at ingestion.
31
+ - An upstream column rename or type change is silent and corrupting. Compare the incoming schema to the expected one and fail on an unexpected difference.
32
+ - **Done when:** a schema change stops the pipeline rather than propagating.
33
+
34
+ 4. Monitor distributions on the columns that matter.
35
+ - Null rate, distinct count, and the quantiles of numeric columns. A null rate moving from 1% to 40% is a broken upstream field, and no error will be raised.
36
+ - **Done when:** key columns have distribution checks with bands.
37
+
38
+ 5. Route alerts to an owner.
39
+ - Every dataset has a name attached. An alert to a shared channel with no owner is an alert nobody acts on.
40
+ - **Done when:** each dataset's alerts have a named owner.
41
+
42
+ 6. Surface the check results next to the data.
43
+ - A dashboard reading a dataset that failed its checks should say so. Otherwise the consumer cannot know.
44
+ - **Done when:** consumers can see the freshness and check status of what they are reading.
45
+
46
+ ## Verification
47
+
48
+ - A deliberately stale partition raises an alert.
49
+ - An upstream column rename stops the pipeline.
50
+ - A spike in the null rate is detected.
51
+ - Every alert has an owner.
@@ -0,0 +1,43 @@
1
+ ---
2
+ name: etl-pipeline-reliability
3
+ description: Build or fix a data pipeline. Use when a scheduled job fails silently, when a rerun duplicates data, or when downstream numbers are wrong.
4
+ ---
5
+
6
+ # ETL Pipeline Reliability
7
+
8
+ ## The two properties
9
+
10
+ Idempotence and observability. A pipeline that cannot be safely re-run cannot be fixed after a failure, and one that fails silently produces wrong numbers that people act on for weeks.
11
+
12
+ ## Workflow
13
+
14
+ 1. Make every run idempotent.
15
+ - Re-running for the same period must produce the same result, not double it. Partition the output by period and replace the partition wholesale, rather than appending.
16
+ - **Done when:** running the same period twice yields identical output.
17
+
18
+ 2. Partition by logical time, not by run time.
19
+ - A job for yesterday should produce yesterday's partition whenever it runs. Keying on the run time makes a backfill impossible and a late run wrong.
20
+ - **Done when:** the output partition is determined by the data's period.
21
+
22
+ 3. Validate at every boundary.
23
+ - Row counts within an expected range, no unexpected nulls in required columns, keys unique, and totals reconciling with the source. Fail the run rather than writing bad data — downstream consumers cannot tell the difference.
24
+ - **Done when:** each stage has assertions that stop the pipeline on violation.
25
+
26
+ 4. Quarantine bad records, do not drop them.
27
+ - Write rejects with the reason to a separate location. Silently dropping rows makes numbers wrong with no trace.
28
+ - **Done when:** every rejected record is retrievable with its reason.
29
+
30
+ 5. Alert on staleness and on volume, not only on errors.
31
+ - The dangerous failure is the job that succeeds while producing nothing, or a tenth of the usual rows. Alert if the newest partition is older than expected, or the volume moves outside its band.
32
+ - **Done when:** an empty successful run raises an alert.
33
+
34
+ 6. Make backfill a normal operation.
35
+ - Parameterise the period and support running a range. A pipeline that cannot backfill cannot recover from an outage.
36
+ - **Done when:** a range backfill runs with one command and produces correct partitions.
37
+
38
+ ## Verification
39
+
40
+ - Re-running a period produces identical output.
41
+ - A deliberately corrupted input fails the run rather than writing.
42
+ - An empty run triggers an alert.
43
+ - A backfill over a week produces correct partitions.
@@ -0,0 +1,43 @@
1
+ ---
2
+ name: exploratory-analysis
3
+ description: Analyse an unfamiliar dataset. Use when receiving new data, before modelling, or when a metric looks wrong.
4
+ ---
5
+
6
+ # Exploratory Data Analysis
7
+
8
+ ## The order
9
+
10
+ Understand the data before asking it questions. An analysis built on a misunderstood column produces a confident wrong answer, and nothing downstream will catch it.
11
+
12
+ ## Workflow
13
+
14
+ 1. Establish the shape and provenance.
15
+ - Row count, column count, types, and where the data came from — including what was filtered before you received it. Data that arrives pre-filtered has a selection bias you must know about.
16
+ - **Done when:** you can state what one row represents, precisely.
17
+
18
+ 2. Profile every column.
19
+ - Missing rate, cardinality, range, and the most frequent values. For dates, the minimum and maximum — future dates and epoch-zero dates are both common and both indicate a bug upstream.
20
+ - **Done when:** every column has been profiled and anomalies are noted.
21
+
22
+ 3. Ask what the missing values mean.
23
+ - Missing at random is very different from missing because the field only applies to some rows, and different again from missing because a system failed for a period. The three demand different handling and only investigation distinguishes them.
24
+ - **Done when:** each column with missing values has a stated explanation.
25
+
26
+ 4. Check the identifiers.
27
+ - Are the keys unique? Do foreign keys resolve? Duplicate rows from a bad join are the most common silent corruption in an analysis, and they inflate every aggregate.
28
+ - **Done when:** key uniqueness and referential integrity have been verified.
29
+
30
+ 5. Plot the distributions before summarising them.
31
+ - A mean describes a unimodal distribution. On a bimodal or heavy-tailed one it describes nothing real. Look at the shape first.
32
+ - **Done when:** every variable you will summarise has been plotted.
33
+
34
+ 6. Look for the seams.
35
+ - A step change in a time series usually means an instrumentation change, not a real change in the world. Check deploy dates before writing a conclusion.
36
+ - **Done when:** discontinuities have been explained or flagged.
37
+
38
+ ## Verification
39
+
40
+ - The meaning of one row is stated.
41
+ - Every column is profiled and every anomaly explained or flagged.
42
+ - Key uniqueness is verified.
43
+ - Conclusions name their caveats.
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: metric-definition
3
+ description: Define a business or product metric. Use when two teams report different numbers for the same thing, or before building a dashboard.
4
+ ---
5
+
6
+ # Metric Definition
7
+
8
+ ## Why the same metric gives two answers
9
+
10
+ Because it was never defined. "Active users" has a dozen reasonable readings, and every team picks one implicitly. The disagreement is discovered in a meeting, months later, after decisions have been made on both numbers.
11
+
12
+ ## Workflow
13
+
14
+ 1. Write the definition in a sentence a non-engineer can check.
15
+ - Include the population, the event, the window, and the exclusions. "Users who performed at least one search in the trailing 28 days, excluding internal accounts and bots, counted by account not by device."
16
+ - **Done when:** two people can independently implement it and agree.
17
+
18
+ 2. Decide the time semantics explicitly.
19
+ - Which timezone, event time or ingestion time, and how late-arriving data is handled. These three choices change the number and are almost never written down.
20
+ - **Done when:** all three are stated.
21
+
22
+ 3. Name the exclusions.
23
+ - Internal users, test accounts, bots, refunded orders, deleted records. Each one is a decision, and a metric that excludes nothing is usually wrong.
24
+ - **Done when:** every exclusion is listed with a reason.
25
+
26
+ 4. Define it once, in one place.
27
+ - A semantic layer or a shared model that every dashboard queries. The same metric computed in three dashboards will give three answers within a quarter.
28
+ - **Done when:** every consumer reads the same definition.
29
+
30
+ 5. State the expected range and alert outside it.
31
+ - A metric with no expected range cannot be sanity-checked. If it doubles overnight, is that success or an instrumentation bug? Usually the latter.
32
+ - **Done when:** an expected band exists and a breach raises a question.
33
+
34
+ 6. Version the definition.
35
+ - When it changes, the historical series changes. Record when and why, and never silently restate history.
36
+ - **Done when:** definition changes are dated and visible on the chart.
37
+
38
+ ## Verification
39
+
40
+ - Two independent implementations produce the same number.
41
+ - The definition names population, event, window, timezone, and exclusions.
42
+ - Every dashboard reads one definition.
@@ -0,0 +1,43 @@
1
+ ---
2
+ name: notebook-to-production
3
+ description: Turn analysis code into something that runs reliably. Use when a notebook needs to become a scheduled job, or when analysis results cannot be reproduced.
4
+ ---
5
+
6
+ # Notebook to Production
7
+
8
+ ## What breaks in the move
9
+
10
+ Hidden state. A notebook's output depends on which cells were run and in what order, and that order is not recorded. Code that works in a notebook frequently does not work when run top to bottom — which is what any scheduler will do.
11
+
12
+ ## Workflow
13
+
14
+ 1. Prove it runs top to bottom first.
15
+ - Restart the kernel and run all. If it fails, the notebook depended on state that no longer exists, and the analysis result is not reproducible either.
16
+ - **Done when:** a fresh kernel produces the same result end to end.
17
+
18
+ 2. Extract logic into functions in a module.
19
+ - The notebook becomes a thin caller. Functions can be tested, imported and reused; cells cannot.
20
+ - **Done when:** the notebook contains calls and plots, not logic.
21
+
22
+ 3. Replace every hardcoded path and credential.
23
+ - Paths, dates and credentials become parameters or configuration. A hardcoded date silently produces stale results forever.
24
+ - **Done when:** nothing environment-specific is embedded in the code.
25
+
26
+ 4. Pin the environment.
27
+ - A lock file. Analysis results depend on library versions, and a silent upgrade changes numbers without changing code.
28
+ - **Done when:** a fresh environment built from the lock file reproduces the result.
29
+
30
+ 5. Add validation and make failure loud.
31
+ - Assertions on row counts, ranges and key uniqueness. A scheduled job that fails silently produces wrong numbers that people act on.
32
+ - **Done when:** a bad input fails the run visibly.
33
+
34
+ 6. Test the extracted functions.
35
+ - Start with the transformations that carry business logic. These are where a wrong result is both most likely and most costly.
36
+ - **Done when:** the core transformations have tests with known inputs and outputs.
37
+
38
+ ## Verification
39
+
40
+ - A fresh environment reproduces the result exactly.
41
+ - The module runs from a scheduler with no notebook.
42
+ - Corrupt input fails loudly.
43
+ - The core transformations have tests.
@@ -0,0 +1,43 @@
1
+ ---
2
+ name: backup-and-recovery
3
+ description: Set up or verify database backups. Use when a system has no tested restore, before a risky migration, or when planning for data loss.
4
+ ---
5
+
6
+ # Backup and Recovery
7
+
8
+ ## The only thing that counts
9
+
10
+ A backup that has never been restored is not a backup. It is an untested hypothesis with a storage bill. The restore is the deliverable.
11
+
12
+ ## Workflow
13
+
14
+ 1. State the two numbers first.
15
+ - Recovery point objective: how much data may be lost. Recovery time objective: how long recovery may take. Everything else follows from these, and without them the design is arbitrary.
16
+ - **Done when:** both numbers are written down and agreed.
17
+
18
+ 2. Choose the mechanism to meet them.
19
+ - Nightly dump: hours of potential loss, simple. Continuous archiving with point-in-time recovery: seconds of loss, more moving parts. A replica is high availability, NOT a backup — it replicates the bad DELETE faithfully and instantly.
20
+ - **Done when:** the mechanism demonstrably meets both numbers.
21
+
22
+ 3. Store copies where a single failure cannot reach them.
23
+ - A different region and a different credential. Ransomware and a compromised account both reach anything the production credential can write, which is why immutable or write-once storage matters.
24
+ - **Done when:** a compromised production credential cannot delete the backups.
25
+
26
+ 4. Restore on a schedule, into a real environment.
27
+ - Automate it, time it, and check row counts and a few known records. Do this monthly at minimum.
28
+ - **Done when:** a restore has been performed and timed within the last month.
29
+
30
+ 5. Back up more than the rows.
31
+ - Schema, roles and grants, extensions, sequence positions, and any encryption keys. A restored database nobody can log into is not recovered.
32
+ - **Done when:** a restore into an empty instance produces a working system with no manual steps.
33
+
34
+ 6. Write the runbook.
35
+ - Exact commands, in order, for someone who did not build the system, under pressure, possibly at night.
36
+ - **Done when:** someone else has followed the runbook successfully without help.
37
+
38
+ ## Verification
39
+
40
+ - A restore into a clean environment has been performed and timed.
41
+ - The restore time meets the recovery time objective.
42
+ - The data loss window meets the recovery point objective.
43
+ - Someone other than the author has run the runbook.
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: connection-pooling
3
+ description: Configure database connections for a service. Use when the database refuses connections, when latency spikes under load, or when a serverless function exhausts connections.
4
+ ---
5
+
6
+ # Connection Pooling
7
+
8
+ ## The counterintuitive part
9
+
10
+ A bigger pool is usually slower. A database has a finite number of cores and disks; connections beyond that queue INSIDE the database, where you cannot see them, instead of in your pool where you can. A pool of ten often outperforms a pool of a hundred on the same hardware.
11
+
12
+ ## Workflow
13
+
14
+ 1. Size from the database, not from the traffic.
15
+ - A reasonable starting point is a small multiple of the database's core count, divided across all application instances. Then measure.
16
+ - **Done when:** the total connections across every instance is below the database's limit with headroom.
17
+
18
+ 2. Count every consumer.
19
+ - Application instances, background workers, migration jobs, admin tools, and monitoring. The limit is shared, and the job that fails to connect is usually the one that runs during a traffic peak.
20
+ - **Done when:** the sum of all configured pools plus reserved superuser slots fits the limit.
21
+
22
+ 3. Set every timeout.
23
+ - Connection acquisition, socket, and statement timeouts. A missing statement timeout lets one runaway query hold a connection indefinitely, and the pool drains one connection at a time until the service is down.
24
+ - **Done when:** no query can run unbounded.
25
+
26
+ 4. Add an external pooler for serverless or high instance counts.
27
+ - Each function invocation opening its own connection exhausts the database immediately. A transaction-mode pooler in front is the standard answer — with the caveat that it breaks session-level features like prepared statements and advisory locks.
28
+ - **Done when:** the pooling mode is chosen and its limitations are accounted for in the code.
29
+
30
+ 5. Return connections deterministically.
31
+ - Acquire and release in a `finally` or an equivalent scope guard. A leaked connection on an error path drains the pool slowly and the symptom appears hours later.
32
+ - **Done when:** every acquisition has a guaranteed release.
33
+
34
+ 6. Instrument the pool.
35
+ - Active, idle, and waiting counts. A rising wait count is the earliest signal of saturation, well before latency shows it.
36
+ - **Done when:** pool saturation is visible on a dashboard.
37
+
38
+ ## Verification
39
+
40
+ - A load test shows stable latency with no connection errors.
41
+ - Total configured connections are within the database limit.
42
+ - A deliberately slow query is terminated by the statement timeout.