fde-framework 0.1.0__py3-none-any.whl

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 (286) hide show
  1. fde/__init__.py +3 -0
  2. fde/architect.py +152 -0
  3. fde/cli.py +2107 -0
  4. fde/costing.py +292 -0
  5. fde/decide.py +297 -0
  6. fde/decompose.py +54 -0
  7. fde/deploy.py +371 -0
  8. fde/emit.py +1309 -0
  9. fde/evolution.py +265 -0
  10. fde/factlog.py +369 -0
  11. fde/framework/approaches/ansible-playbook.md +22 -0
  12. fde/framework/approaches/assisted-deterministic.md +37 -0
  13. fde/framework/approaches/audit-only.md +23 -0
  14. fde/framework/approaches/boundary-and-audit.md +18 -0
  15. fde/framework/approaches/cascade.md +32 -0
  16. fde/framework/approaches/classical-ml.md +21 -0
  17. fde/framework/approaches/compose.md +18 -0
  18. fde/framework/approaches/decision-log.md +21 -0
  19. fde/framework/approaches/deterministic-masking.md +18 -0
  20. fde/framework/approaches/deterministic.md +25 -0
  21. fde/framework/approaches/direct-call.md +10 -0
  22. fde/framework/approaches/episodic-store.md +17 -0
  23. fde/framework/approaches/explainability-record.md +14 -0
  24. fde/framework/approaches/field-match.md +15 -0
  25. fde/framework/approaches/finetune.md +29 -0
  26. fde/framework/approaches/fixed-sequence.md +19 -0
  27. fde/framework/approaches/gitops.md +18 -0
  28. fde/framework/approaches/governed-tools.md +18 -0
  29. fde/framework/approaches/graph-retrieval.md +22 -0
  30. fde/framework/approaches/judged.md +15 -0
  31. fde/framework/approaches/keyword-search.md +11 -0
  32. fde/framework/approaches/kubernetes-manifests.md +19 -0
  33. fde/framework/approaches/labelled-metrics.md +14 -0
  34. fde/framework/approaches/llm-extraction.md +26 -0
  35. fde/framework/approaches/llm-scrubbing.md +20 -0
  36. fde/framework/approaches/llm.md +23 -0
  37. fde/framework/approaches/local-embedding.md +28 -0
  38. fde/framework/approaches/managed-api.md +49 -0
  39. fde/framework/approaches/managed-embedding.md +22 -0
  40. fde/framework/approaches/manual-runbook.md +32 -0
  41. fde/framework/approaches/model-planner.md +19 -0
  42. fde/framework/approaches/ocr-pipeline.md +13 -0
  43. fde/framework/approaches/optimisation-reasoning.md +30 -0
  44. fde/framework/approaches/optimisation.md +19 -0
  45. fde/framework/approaches/passthrough.md +11 -0
  46. fde/framework/approaches/role-scoped-authority.md +19 -0
  47. fde/framework/approaches/segmentation.md +29 -0
  48. fde/framework/approaches/self-hosted.md +38 -0
  49. fde/framework/approaches/serverless-gpu.md +27 -0
  50. fde/framework/approaches/speech-transcription.md +21 -0
  51. fde/framework/approaches/structured-logs.md +11 -0
  52. fde/framework/approaches/systemd-unit.md +30 -0
  53. fde/framework/approaches/terraform-module.md +22 -0
  54. fde/framework/approaches/text-extraction.md +14 -0
  55. fde/framework/approaches/traced.md +24 -0
  56. fde/framework/approaches/vector-search.md +17 -0
  57. fde/framework/approaches/video-ingestion.md +16 -0
  58. fde/framework/approaches/windowed-ingestion.md +25 -0
  59. fde/framework/approaches/working-state.md +13 -0
  60. fde/framework/cases/churn-scoring.md +45 -0
  61. fde/framework/cases/route-planning.md +44 -0
  62. fde/framework/cases/structured-extraction.md +48 -0
  63. fde/framework/cases/studio-style.md +46 -0
  64. fde/framework/components/accountability.md +20 -0
  65. fde/framework/components/deployment.md +19 -0
  66. fde/framework/components/embedding.md +23 -0
  67. fde/framework/components/evaluation.md +13 -0
  68. fde/framework/components/governance.md +19 -0
  69. fde/framework/components/integration.md +13 -0
  70. fde/framework/components/memory.md +21 -0
  71. fde/framework/components/observability.md +13 -0
  72. fde/framework/components/perception.md +15 -0
  73. fde/framework/components/planning.md +15 -0
  74. fde/framework/components/provisioning.md +17 -0
  75. fde/framework/components/reasoning.md +20 -0
  76. fde/framework/components/redaction.md +18 -0
  77. fde/framework/components/representation.md +13 -0
  78. fde/framework/components/retrieval.md +13 -0
  79. fde/framework/components/serving.md +20 -0
  80. fde/framework/dimensions/accelerator.md +29 -0
  81. fde/framework/dimensions/access_model.md +25 -0
  82. fde/framework/dimensions/arrival_rate.md +19 -0
  83. fde/framework/dimensions/availability_target.md +23 -0
  84. fde/framework/dimensions/cheap_path_coverage.md +21 -0
  85. fde/framework/dimensions/confidence_calibrated.md +30 -0
  86. fde/framework/dimensions/container_competence.md +22 -0
  87. fde/framework/dimensions/corpus_size.md +13 -0
  88. fde/framework/dimensions/data_residency.md +36 -0
  89. fde/framework/dimensions/environment_lifetime.md +19 -0
  90. fde/framework/dimensions/existing_cluster.md +22 -0
  91. fde/framework/dimensions/existing_iac_tool.md +25 -0
  92. fde/framework/dimensions/external_systems.md +15 -0
  93. fde/framework/dimensions/hosting.md +45 -0
  94. fde/framework/dimensions/human_waiting.md +41 -0
  95. fde/framework/dimensions/input_format.md +29 -0
  96. fde/framework/dimensions/interpretability_required.md +24 -0
  97. fde/framework/dimensions/labelled_count.md +15 -0
  98. fde/framework/dimensions/latency_budget_ms.md +16 -0
  99. fde/framework/dimensions/licence_posture.md +28 -0
  100. fde/framework/dimensions/operates_after_handover.md +25 -0
  101. fde/framework/dimensions/output_shape.md +29 -0
  102. fde/framework/dimensions/provisioning_api.md +18 -0
  103. fde/framework/dimensions/query_pattern.md +25 -0
  104. fde/framework/dimensions/recall_span.md +22 -0
  105. fde/framework/dimensions/sensitivity_present.md +22 -0
  106. fde/framework/interfaces/Generator.md +5 -0
  107. fde/framework/interfaces/Guard.md +5 -0
  108. fde/framework/interfaces/Mapper.md +5 -0
  109. fde/framework/interfaces/ModelServer.md +5 -0
  110. fde/framework/interfaces/Parser.md +5 -0
  111. fde/framework/interfaces/Planner.md +5 -0
  112. fde/framework/interfaces/Retriever.md +5 -0
  113. fde/framework/interfaces/Scorer.md +5 -0
  114. fde/framework/interfaces/Store.md +5 -0
  115. fde/framework/interfaces/ToolBoundary.md +5 -0
  116. fde/framework/interfaces/Tracer.md +5 -0
  117. fde/framework/locales/eu-gdpr.md +51 -0
  118. fde/framework/locales/in-dpdp.md +46 -0
  119. fde/framework/patterns/ansible-playbook.md +9 -0
  120. fde/framework/patterns/assisted-deterministic.md +11 -0
  121. fde/framework/patterns/audit-only.md +9 -0
  122. fde/framework/patterns/boundary-and-audit.md +12 -0
  123. fde/framework/patterns/cascade-reasoning.md +10 -0
  124. fde/framework/patterns/cascade-representation.md +10 -0
  125. fde/framework/patterns/cascade-retrieval.md +10 -0
  126. fde/framework/patterns/classical-ml-reasoning.md +15 -0
  127. fde/framework/patterns/classical-ml.md +13 -0
  128. fde/framework/patterns/compose.md +9 -0
  129. fde/framework/patterns/decision-log.md +9 -0
  130. fde/framework/patterns/deterministic-masking.md +9 -0
  131. fde/framework/patterns/deterministic.md +12 -0
  132. fde/framework/patterns/direct-call.md +12 -0
  133. fde/framework/patterns/episodic-store.md +13 -0
  134. fde/framework/patterns/explainability-record.md +9 -0
  135. fde/framework/patterns/field-match.md +12 -0
  136. fde/framework/patterns/finetune-representation.md +14 -0
  137. fde/framework/patterns/finetune.md +12 -0
  138. fde/framework/patterns/fixed-sequence.md +12 -0
  139. fde/framework/patterns/gitops.md +9 -0
  140. fde/framework/patterns/governed-tools.md +13 -0
  141. fde/framework/patterns/graph-retrieval.md +14 -0
  142. fde/framework/patterns/judged.md +14 -0
  143. fde/framework/patterns/keyword-search.md +12 -0
  144. fde/framework/patterns/kubernetes-manifests.md +9 -0
  145. fde/framework/patterns/labelled-metrics.md +13 -0
  146. fde/framework/patterns/llm-representation.md +17 -0
  147. fde/framework/patterns/llm-scrubbing.md +9 -0
  148. fde/framework/patterns/llm.md +12 -0
  149. fde/framework/patterns/local-embedding.md +9 -0
  150. fde/framework/patterns/managed-api.md +12 -0
  151. fde/framework/patterns/managed-embedding.md +9 -0
  152. fde/framework/patterns/manual-runbook.md +9 -0
  153. fde/framework/patterns/model-planner.md +13 -0
  154. fde/framework/patterns/ocr-pipeline.md +13 -0
  155. fde/framework/patterns/optimisation-reasoning.md +15 -0
  156. fde/framework/patterns/optimisation.md +13 -0
  157. fde/framework/patterns/passthrough.md +12 -0
  158. fde/framework/patterns/role-scoped-authority.md +9 -0
  159. fde/framework/patterns/segmentation.md +12 -0
  160. fde/framework/patterns/self-hosted.md +14 -0
  161. fde/framework/patterns/serverless-gpu.md +12 -0
  162. fde/framework/patterns/speech-transcription.md +10 -0
  163. fde/framework/patterns/structured-logs.md +12 -0
  164. fde/framework/patterns/systemd-unit.md +9 -0
  165. fde/framework/patterns/terraform-module.md +9 -0
  166. fde/framework/patterns/text-extraction.md +12 -0
  167. fde/framework/patterns/traced.md +13 -0
  168. fde/framework/patterns/vector-search.md +14 -0
  169. fde/framework/patterns/video-ingestion.md +9 -0
  170. fde/framework/patterns/windowed-ingestion.md +12 -0
  171. fde/framework/patterns/working-state.md +12 -0
  172. fde/framework/stacks/langgraph.md +9 -0
  173. fde/framework/stacks/local-judge.md +9 -0
  174. fde/framework/stacks/mcp.md +9 -0
  175. fde/framework/stacks/ollama.md +19 -0
  176. fde/framework/stacks/openai-judge.md +9 -0
  177. fde/framework/stacks/opentelemetry.md +9 -0
  178. fde/framework/stacks/ortools.md +9 -0
  179. fde/framework/stacks/pgvector.md +9 -0
  180. fde/framework/stacks/plain-python.md +9 -0
  181. fde/framework/stacks/qdrant.md +9 -0
  182. fde/framework/stacks/tesseract.md +9 -0
  183. fde/framework/stacks/vllm.md +9 -0
  184. fde/framework/stacks/whisper.md +15 -0
  185. fde/framework/stacks/xgboost.md +9 -0
  186. fde/framework/templates/accountability/decision-log.plain.py.j2 +64 -0
  187. fde/framework/templates/accountability/explainability-record.plain.py.j2 +90 -0
  188. fde/framework/templates/deployment/compose.plain.py.j2 +36 -0
  189. fde/framework/templates/deployment/kubernetes-manifests.plain.py.j2 +36 -0
  190. fde/framework/templates/deployment/systemd-unit.plain.py.j2 +36 -0
  191. fde/framework/templates/embedding/local-embedding.plain.py.j2 +71 -0
  192. fde/framework/templates/embedding/managed-embedding.plain.py.j2 +76 -0
  193. fde/framework/templates/evaluation/field-match.plain.py.j2 +146 -0
  194. fde/framework/templates/evaluation/judged.local-judge.py.j2 +100 -0
  195. fde/framework/templates/evaluation/judged.openai-judge.py.j2 +70 -0
  196. fde/framework/templates/evaluation/judged.plain.py.j2 +89 -0
  197. fde/framework/templates/evaluation/labelled-metrics.plain.py.j2 +64 -0
  198. fde/framework/templates/evaluation/labelled-metrics.xgboost.py.j2 +72 -0
  199. fde/framework/templates/governance/audit-only.plain.py.j2 +98 -0
  200. fde/framework/templates/governance/boundary-and-audit.plain.py.j2 +142 -0
  201. fde/framework/templates/governance/role-scoped-authority.plain.py.j2 +63 -0
  202. fde/framework/templates/integration/direct-call.plain.py.j2 +63 -0
  203. fde/framework/templates/integration/governed-tools.mcp.py.j2 +124 -0
  204. fde/framework/templates/integration/governed-tools.plain.py.j2 +153 -0
  205. fde/framework/templates/memory/episodic-store.pgvector.py.j2 +118 -0
  206. fde/framework/templates/memory/episodic-store.plain.py.j2 +147 -0
  207. fde/framework/templates/memory/working-state.plain.py.j2 +48 -0
  208. fde/framework/templates/observability/structured-logs.plain.py.j2 +61 -0
  209. fde/framework/templates/observability/traced.opentelemetry.py.j2 +65 -0
  210. fde/framework/templates/observability/traced.plain.py.j2 +132 -0
  211. fde/framework/templates/perception/ocr-pipeline.plain.py.j2 +71 -0
  212. fde/framework/templates/perception/ocr-pipeline.tesseract.py.j2 +80 -0
  213. fde/framework/templates/perception/passthrough.plain.py.j2 +41 -0
  214. fde/framework/templates/perception/speech-transcription.plain.py.j2 +37 -0
  215. fde/framework/templates/perception/speech-transcription.whisper.py.j2 +39 -0
  216. fde/framework/templates/perception/text-extraction.plain.py.j2 +88 -0
  217. fde/framework/templates/perception/video-ingestion.plain.py.j2 +35 -0
  218. fde/framework/templates/perception/windowed-ingestion.plain.py.j2 +69 -0
  219. fde/framework/templates/planning/fixed-sequence.plain.py.j2 +46 -0
  220. fde/framework/templates/planning/model-planner.langgraph.py.j2 +89 -0
  221. fde/framework/templates/planning/model-planner.plain.py.j2 +82 -0
  222. fde/framework/templates/planning/optimisation.ortools.py.j2 +90 -0
  223. fde/framework/templates/planning/optimisation.plain.py.j2 +71 -0
  224. fde/framework/templates/provisioning/ansible-playbook.plain.py.j2 +29 -0
  225. fde/framework/templates/provisioning/gitops.plain.py.j2 +29 -0
  226. fde/framework/templates/provisioning/manual-runbook.plain.py.j2 +29 -0
  227. fde/framework/templates/provisioning/terraform-module.plain.py.j2 +29 -0
  228. fde/framework/templates/reasoning/cascade.plain.py.j2 +86 -0
  229. fde/framework/templates/reasoning/classical-ml.plain.py.j2 +74 -0
  230. fde/framework/templates/reasoning/classical-ml.xgboost.py.j2 +104 -0
  231. fde/framework/templates/reasoning/finetune.plain.py.j2 +73 -0
  232. fde/framework/templates/reasoning/llm.plain.py.j2 +114 -0
  233. fde/framework/templates/reasoning/optimisation.ortools.py.j2 +90 -0
  234. fde/framework/templates/reasoning/optimisation.plain.py.j2 +58 -0
  235. fde/framework/templates/redaction/deterministic-masking.plain.py.j2 +44 -0
  236. fde/framework/templates/redaction/llm-scrubbing.plain.py.j2 +40 -0
  237. fde/framework/templates/representation/assisted.plain.py.j2 +86 -0
  238. fde/framework/templates/representation/cascade.plain.py.j2 +119 -0
  239. fde/framework/templates/representation/classical-ml.plain.py.j2 +74 -0
  240. fde/framework/templates/representation/classical-ml.xgboost.py.j2 +104 -0
  241. fde/framework/templates/representation/deterministic.plain.py.j2 +101 -0
  242. fde/framework/templates/representation/finetune.plain.py.j2 +68 -0
  243. fde/framework/templates/representation/llm.plain.py.j2 +94 -0
  244. fde/framework/templates/representation/segmentation.plain.py.j2 +68 -0
  245. fde/framework/templates/retrieval/cascade.plain.py.j2 +86 -0
  246. fde/framework/templates/retrieval/graph-retrieval.pgvector.py.j2 +88 -0
  247. fde/framework/templates/retrieval/graph-retrieval.plain.py.j2 +74 -0
  248. fde/framework/templates/retrieval/graph-retrieval.qdrant.py.j2 +71 -0
  249. fde/framework/templates/retrieval/keyword-search.plain.py.j2 +104 -0
  250. fde/framework/templates/retrieval/vector-search.pgvector.py.j2 +100 -0
  251. fde/framework/templates/retrieval/vector-search.plain.py.j2 +84 -0
  252. fde/framework/templates/retrieval/vector-search.qdrant.py.j2 +60 -0
  253. fde/framework/templates/serving/managed-api.plain.py.j2 +74 -0
  254. fde/framework/templates/serving/self-hosted.ollama.py.j2 +47 -0
  255. fde/framework/templates/serving/self-hosted.plain.py.j2 +117 -0
  256. fde/framework/templates/serving/self-hosted.vllm.py.j2 +77 -0
  257. fde/framework/templates/serving/serverless-gpu.plain.py.j2 +62 -0
  258. fde/gates.py +480 -0
  259. fde/graph.py +435 -0
  260. fde/implement.py +250 -0
  261. fde/intake/__init__.py +0 -0
  262. fde/intake/answers.py +154 -0
  263. fde/intake/documents.py +121 -0
  264. fde/intake/interview.py +218 -0
  265. fde/intake/llm_reader.py +336 -0
  266. fde/intake/prose.py +387 -0
  267. fde/intake/samples.py +369 -0
  268. fde/models/__init__.py +0 -0
  269. fde/models/base.py +86 -0
  270. fde/models/fact.py +37 -0
  271. fde/models/profile.py +159 -0
  272. fde/models/respondent.py +34 -0
  273. fde/models/schema.py +430 -0
  274. fde/moves.py +136 -0
  275. fde/ops.py +349 -0
  276. fde/predicate.py +106 -0
  277. fde/realization.py +109 -0
  278. fde/registry.py +162 -0
  279. fde/scan.py +479 -0
  280. fde/space.py +172 -0
  281. fde/workflow.py +233 -0
  282. fde_framework-0.1.0.dist-info/METADATA +449 -0
  283. fde_framework-0.1.0.dist-info/RECORD +286 -0
  284. fde_framework-0.1.0.dist-info/WHEEL +4 -0
  285. fde_framework-0.1.0.dist-info/entry_points.txt +2 -0
  286. fde_framework-0.1.0.dist-info/licenses/LICENSE +202 -0
@@ -0,0 +1,23 @@
1
+ ---
2
+ id: audit-only
3
+ name: Audit trail
4
+ complexity: 0
5
+ components: [governance]
6
+ applies_when: [data_residency == may_leave]
7
+ avoid_when: [access_model == role_based, data_residency == cannot_leave, hosting == air-gapped]
8
+ evidence: {case_ids: [churn-scoring], confidence: high, last_verified: 2026-08-25}
9
+ ---
10
+ A record of what happened, without a boundary around where it happened.
11
+
12
+ The right answer where nothing forbids egress but actions are still taken on
13
+ someone's behalf. Enforcing placement costs real complexity -- split
14
+ deployments, pinned components, a build that fails on a topology change -- and
15
+ paying for it when nothing requires it is the over-engineering the residency
16
+ question exists to prevent.
17
+
18
+ Residency and isolation are not the same requirement, and conflating them is a
19
+ known and expensive mistake. Data staying in a region satisfies one; only
20
+ staying inside a boundary satisfies the other.
21
+
22
+ What does not change: the record names the human as subject and the agent as
23
+ actor, and the trail never fails open into silence.
@@ -0,0 +1,18 @@
1
+ ---
2
+ id: boundary-and-audit
3
+ name: Boundary and audit
4
+ complexity: 1
5
+ components: [governance]
6
+ applies_when: [data_residency == cannot_leave, hosting == air-gapped]
7
+ avoid_when: [access_model == role_based, data_residency == may_leave]
8
+ evidence: {case_ids: [structured-extraction], confidence: high, last_verified: 2026-08-21}
9
+ ---
10
+ Not needed where nothing forbids egress -- a boundary around data free to
11
+ move is ceremony. Placement enforced structurally, and an append-only record of what happened.
12
+
13
+ Entitlements are inherited, never granted: what an agent may do is the
14
+ intersection of what the delegating person may do, what it is scoped to, and
15
+ what the tool requires. Never a union.
16
+
17
+ The audit names the human as subject and the agent as actor. A record saying an
18
+ agent issued a refund has lost the accountability chain.
@@ -0,0 +1,32 @@
1
+ ---
2
+ id: cascade
3
+ name: Cascade
4
+ complexity: 2
5
+ components: [representation, retrieval, reasoning]
6
+ applies_when: [confidence_calibrated == true and cheap_path_coverage < 0.95]
7
+ avoid_when: [confidence_calibrated == false, interpretability_required == true]
8
+ evidence: {case_ids: [structured-extraction], confidence: medium, last_verified: 2026-08-24}
9
+ ---
10
+ Do the cheap confident work; escalate the rest.
11
+
12
+ Four unrelated lines of practice describe this same shape. Entity resolution
13
+ runs deterministic rules on records carrying an exact identifier and something
14
+ probabilistic on the remainder. Model cascades try the cheapest model and
15
+ escalate only what fails a threshold, reported at roughly half to four-fifths
16
+ off while holding most of the quality. Active learning scores without labels and
17
+ sends the least confident to a human. Tiered memory keeps cheaply and promotes
18
+ deliberately.
19
+
20
+ They are one pattern, and the payoff compounds: **the records the cheap tier
21
+ could not settle are simultaneously the escalation path and the queue worth a
22
+ human's attention** -- and once verified, the additions to the golden set. One
23
+ residue, three uses.
24
+
25
+ What separates a cascade from a router is that **the decision is made on the
26
+ output, not the input**. The cheap tier attempts the work and is then judged.
27
+
28
+ Which makes calibration the whole thing rather than a detail. Confidence scores
29
+ are typically miscalibrated, and a threshold tuned on one workload routinely
30
+ fails on the next, so a cascade without a measured error rate is a cost saving
31
+ with an unknown liability attached. Ruled out where a decision must be
32
+ explained: "the cheap path was confident" is not a reason anyone accepts.
@@ -0,0 +1,21 @@
1
+ ---
2
+ id: classical-ml
3
+ name: Classical ML
4
+ complexity: 1
5
+ components: [representation, reasoning]
6
+ applies_when:
7
+ - output_shape == classification
8
+ - output_shape == ranking
9
+ - output_shape == decision and labelled_count >= 1000
10
+ avoid_when: [output_shape == freeform, output_shape == structured]
11
+ evidence: {case_ids: [churn-scoring], confidence: high, last_verified: 2026-08-21}
12
+ ---
13
+ Gradient-boosted trees and their relatives on tabular data.
14
+
15
+ Still the right answer for a numeric or class outcome from columns, and it wins
16
+ on the three axes that usually decide: it trains on far less data, it answers in
17
+ single-digit milliseconds, and it can say which features moved the prediction.
18
+
19
+ That last one is often decisive rather than nice to have. A requirement to
20
+ explain a decision to a regulator rules out approaches that cannot produce a
21
+ reason, whatever their accuracy.
@@ -0,0 +1,18 @@
1
+ ---
2
+ id: compose
3
+ name: Compose
4
+ complexity: 1
5
+ components: [deployment]
6
+ applies_when: [container_competence == true]
7
+ avoid_when: [existing_cluster == true, container_competence == false]
8
+ evidence: {case_ids: [studio-style], confidence: high, last_verified: 2026-08-25}
9
+ ---
10
+ Several containers on one host, declared together.
11
+
12
+ The right rung for more than one long-lived process where multi-node scheduling
13
+ is not required. Isolation and reproducible dependencies without a control
14
+ plane, an etcd or an upgrade treadmill.
15
+
16
+ Its limit is honest and worth stating up front: one host. When that host is
17
+ being restarted, the service is down, and if that is unacceptable the next rung
18
+ is the answer rather than a workaround here.
@@ -0,0 +1,21 @@
1
+ ---
2
+ id: decision-log
3
+ name: Decision log
4
+ complexity: 0
5
+ components: [accountability]
6
+ applies_when: [interpretability_required == true]
7
+ avoid_when:
8
+ - output_shape == freeform
9
+ - output_shape == classification
10
+ - output_shape == ranking
11
+ evidence: {case_ids: [structured-extraction], confidence: high, last_verified: 2026-08-25}
12
+ ---
13
+ Every decision kept with its inputs and the rule that produced it.
14
+
15
+ Enough where the decision came from a rule: replaying the rule against the
16
+ recorded inputs reproduces the outcome exactly, which is the strongest form of
17
+ explanation available and needs no model to generate it.
18
+
19
+ Not enough where the decision came from a model. There, the inputs and the
20
+ outcome do not reconstruct the reasoning, and something that attributes the
21
+ outcome to its drivers is required instead.
@@ -0,0 +1,18 @@
1
+ ---
2
+ id: deterministic-masking
3
+ name: Deterministic masking
4
+ complexity: 0
5
+ components: [redaction]
6
+ applies_when: [sensitivity_present == true]
7
+ avoid_when: [sensitivity_present == false]
8
+ evidence: {case_ids: [structured-extraction], confidence: medium, last_verified: 2026-08-30}
9
+ ---
10
+ Named fields replaced by stable hashes, before anything downstream sees the
11
+ record.
12
+
13
+ Deterministic on purpose, twice over. The same value masks to the same token,
14
+ so joins and deduplication survive masking -- a random mask would quietly
15
+ break every downstream equality. And the field list is declared, not
16
+ detected: a model guessing which fields are sensitive is a model that will
17
+ one day guess wrong in the direction that matters, so the list comes from the
18
+ contract the client's own samples marked and the FDE confirmed.
@@ -0,0 +1,25 @@
1
+ ---
2
+ id: deterministic
3
+ name: Deterministic
4
+ complexity: 0
5
+ components: [representation]
6
+ applies_when: [output_shape == structured, output_shape == decision]
7
+ avoid_when:
8
+ - output_shape == freeform
9
+ - output_shape == ranking
10
+ - cheap_path_coverage < 0.95
11
+ evidence: {case_ids: [structured-extraction], confidence: high, last_verified: 2026-08-21}
12
+ ---
13
+ Entity masters, regular expressions, generated code, explicit mappings.
14
+
15
+ Where correctness is not negotiable -- mapping a field, deriving a figure,
16
+ resolving an identifier -- this is the right tool and a model is not. "The
17
+ model will handle it" is the wrong answer in a regulated setting, and it is
18
+ usually the wrong answer everywhere else that a rule can be written down.
19
+
20
+ Right where it covers the work. Where a meaningful share of records carry no
21
+ exact identifier, rules alone finish the ones they can and drop the rest
22
+ quietly -- which is why coverage is asked rather than assumed.
23
+
24
+ Cheapest to run, cheapest to explain, and it fails loudly rather than
25
+ plausibly. Reach past it only when the mapping genuinely cannot be stated.
@@ -0,0 +1,10 @@
1
+ ---
2
+ id: direct-call
3
+ name: Direct call
4
+ complexity: 0
5
+ components: [integration]
6
+ applies_when: [external_systems < 2]
7
+ avoid_when: [external_systems > 1]
8
+ evidence: {case_ids: [churn-scoring], confidence: high, last_verified: 2026-08-21}
9
+ ---
10
+ One system, called directly. A registry for a single endpoint is ceremony.
@@ -0,0 +1,17 @@
1
+ ---
2
+ id: episodic-store
3
+ name: Episodic store
4
+ complexity: 2
5
+ components: [memory]
6
+ applies_when: [recall_span == across_sessions]
7
+ avoid_when: [recall_span == within_turn, recall_span == within_session]
8
+ evidence: {case_ids: [studio-style], confidence: medium, last_verified: 2026-08-21}
9
+ ---
10
+ What the system learned, kept beyond the session that produced it.
11
+
12
+ A different system from working state, with a different write policy, and it
13
+ fails differently: a wrong belief written here is permanent and will be recalled
14
+ with confidence. What gets promoted from working state to long-term is the
15
+ decision that matters, and it should be deliberate rather than automatic.
16
+
17
+ Holds client data by definition, so it inherits residency -- embeddings too.
@@ -0,0 +1,14 @@
1
+ ---
2
+ id: explainability-record
3
+ name: Explainability record
4
+ complexity: 1
5
+ components: [accountability]
6
+ applies_when: [interpretability_required == true]
7
+ avoid_when: [interpretability_required == false]
8
+ evidence: {case_ids: [churn-scoring], confidence: high, last_verified: 2026-08-21}
9
+ ---
10
+ Every decision keeps what drove it, in a form somebody outside the team can read
11
+ months later.
12
+
13
+ Built in from the start or not at all: reconstructing why a model decided
14
+ something after the fact is guesswork wearing a report's formatting.
@@ -0,0 +1,15 @@
1
+ ---
2
+ id: field-match
3
+ name: Field-level matching
4
+ complexity: 0
5
+ components: [evaluation]
6
+ applies_when: [output_shape == structured]
7
+ avoid_when: [output_shape == freeform]
8
+ evidence: {case_ids: [structured-extraction], confidence: high, last_verified: 2026-08-21}
9
+ ---
10
+ Compare each field against a verified answer. Exact where the field is exact,
11
+ tolerant where it is a date or an amount.
12
+
13
+ Gives a per-field breakdown rather than one number, which is what tells you
14
+ what to build next. Eighty-eight percent accurate says how often you fail; the
15
+ shape of the twelve percent says why.
@@ -0,0 +1,29 @@
1
+ ---
2
+ id: finetune
3
+ name: Fine-tuning
4
+ complexity: 3
5
+ components: [reasoning, representation]
6
+ applies_when: [output_shape == freeform and labelled_count >= 1000]
7
+ avoid_when: [output_shape == classification, output_shape == decision]
8
+ evidence: {case_ids: [structured-extraction], confidence: medium, last_verified: 2026-08-21}
9
+ ---
10
+ Adapting a model's behaviour: tone, house style, output shape, schema mapping.
11
+
12
+ **For behaviour, never for facts.** Fine-tuning teaches a model *how* to
13
+ respond, not *what* is true; anything that changes weekly belongs in retrieval,
14
+ not in weights. Train only on verified pairs -- unverified rows are an asset,
15
+ but they are mined rather than trained on.
16
+
17
+ **Reached by graduation or override, never by the first decision.** The
18
+ prompted model is simpler and applies wherever this does, so
19
+ simplest-first always chooses it first -- which is this corpus's own
20
+ rule: try the model before adapting it, and let the measured gap argue
21
+ for adaptation. Until calibrated graduation triggers exist, the road
22
+ here is `fde override`, with the measured gap as the reason.
23
+
24
+ The label count is in the applies condition because it is the whole question:
25
+ adaptation without enough verified pairs is not available, whatever the output
26
+ shape, and an approach that never asked how many labels exist would recommend
27
+ training on hope.
28
+
29
+ Expensive to reverse: a change means retraining and re-evaluating. Earn it.
@@ -0,0 +1,19 @@
1
+ ---
2
+ id: fixed-sequence
3
+ name: Fixed sequence
4
+ complexity: 0
5
+ components: [planning]
6
+ applies_when: [always]
7
+ avoid_when: [output_shape == decision]
8
+ evidence: {case_ids: [structured-extraction], confidence: high, last_verified: 2026-08-21}
9
+ ---
10
+ Steps written in advance, in order, by a person.
11
+
12
+ Every path is enumerable, so every path can be tested. Cost and latency are
13
+ bounded at design time rather than discovered in production. Where the work
14
+ genuinely has a fixed shape this is not a lesser option, it is the correct one,
15
+ and reaching past it is how a pipeline acquires a control loop it never needed.
16
+
17
+ The question worth asking is not whether this counts as an agent. It is whether
18
+ the next step can depend on the last one in a way nobody enumerated -- and if
19
+ it cannot, this is the answer.
@@ -0,0 +1,18 @@
1
+ ---
2
+ id: gitops
3
+ name: Manifests in version control
4
+ complexity: 0
5
+ components: [provisioning]
6
+ applies_when: [existing_cluster == true]
7
+ avoid_when: [existing_cluster == false]
8
+ evidence: {case_ids: [route-planning], confidence: medium, last_verified: 2026-08-25}
9
+ ---
10
+ The desired state in a repository, reconciled onto a cluster that already exists.
11
+
12
+ "Neither provisioner" as a real answer. Where the infrastructure is somebody
13
+ else's problem, adding one provisions nothing and gives an FDE a second thing to
14
+ hand over.
15
+
16
+ What it buys instead is that the deployed state is reviewable and revertable by
17
+ whoever already reviews changes, which is usually the property people wanted
18
+ from a provisioning tool in the first place.
@@ -0,0 +1,18 @@
1
+ ---
2
+ id: governed-tools
3
+ name: Governed tool boundary
4
+ complexity: 1
5
+ components: [integration]
6
+ applies_when: [external_systems > 1]
7
+ avoid_when: [external_systems < 2]
8
+ evidence: {case_ids: [route-planning], confidence: high, last_verified: 2026-08-21}
9
+ ---
10
+ One entry point through which every outward call passes, each tool declaring a
11
+ typed schema, the scope it requires, and whether it changes anything.
12
+
13
+ Past the first system this stops being tidiness: it is the only place
14
+ authentication, authorisation and audit can be enforced once instead of per
15
+ caller. The mutative flag is what lets the autonomy move find the steps needing
16
+ a gate and an idempotency key, without anyone remembering to add them.
17
+
18
+ An unregistered tool cannot be called. That is the property, not a policy.
@@ -0,0 +1,22 @@
1
+ ---
2
+ id: graph-retrieval
3
+ name: Graph retrieval
4
+ complexity: 3
5
+ components: [retrieval]
6
+ applies_when: [query_pattern == multi_hop]
7
+ avoid_when: [query_pattern == lookup, query_pattern == comparative]
8
+ evidence: {case_ids: [structured-extraction], confidence: medium, last_verified: 2026-08-21}
9
+ ---
10
+ Explicit entities and edges, traversed at query time.
11
+
12
+ Worth its cost only where similarity search structurally cannot answer -- how
13
+ two things connect, rather than which text resembles a query. On single-fact
14
+ lookup it measurably loses to plain chunks, so this is a specialised instrument
15
+ rather than an upgrade.
16
+
17
+ The costs are real: multi-pass extraction to build it, two to three times the
18
+ end-to-end latency to use it, and an index that grows super-linearly, which is
19
+ what makes incremental updates painful on a corpus that changes.
20
+
21
+ Published gains also warrant scepticism -- judge position bias has been shown to
22
+ swing reported win rates by tens of points. Measure on your own traffic.
@@ -0,0 +1,15 @@
1
+ ---
2
+ id: judged
3
+ name: Judged
4
+ complexity: 2
5
+ components: [evaluation]
6
+ applies_when: [output_shape == freeform]
7
+ avoid_when: [output_shape == structured, output_shape == classification]
8
+ evidence: {case_ids: [studio-style], confidence: medium, last_verified: 2026-08-21}
9
+ ---
10
+ A model grades the output against a rubric, calibrated against human agreement
11
+ before anyone trusts it.
12
+
13
+ Two rules. The author never grades itself. And where nothing may leave, the
14
+ judge runs locally -- a metric that needs a hosted model is not a metric you
15
+ have, and finding that out at deployment is too late.
@@ -0,0 +1,11 @@
1
+ ---
2
+ id: keyword-search
3
+ name: Keyword search
4
+ complexity: 0
5
+ components: [retrieval]
6
+ applies_when: [query_pattern == lookup]
7
+ avoid_when: [query_pattern == multi_hop]
8
+ evidence: {case_ids: [structured-extraction], confidence: high, last_verified: 2026-08-21}
9
+ ---
10
+ Lexical matching. Unfashionable, cheap, and hard to beat when people search for
11
+ terms that actually appear -- identifiers, part numbers, names.
@@ -0,0 +1,19 @@
1
+ ---
2
+ id: kubernetes-manifests
3
+ name: Cluster manifests
4
+ complexity: 2
5
+ components: [deployment]
6
+ applies_when: [existing_cluster == true, external_systems > 2]
7
+ avoid_when: [container_competence == false and existing_cluster == false]
8
+ evidence: {case_ids: [route-planning], confidence: high, last_verified: 2026-08-25}
9
+ ---
10
+ Manifests applied to a cluster that already exists.
11
+
12
+ Cheap when the cluster is there and somebody else patches it -- the tenth
13
+ workload costs almost nothing, which is the entire argument for a platform.
14
+
15
+ Expensive when it is not. Standing up a cluster for one deployment buys a
16
+ control plane, an upgrade cadence and a set of failure modes for something that
17
+ wanted a service unit, and the cost lands on whoever is still there in a year.
18
+
19
+ Competence gates this only where no cluster exists yet. A cluster already running means somebody operates it -- manifests are how that shop deploys, whatever this team's container practice, and blocking the only cluster-native option on the applying team's skills would leave a cluster shop with no way to deploy at all.
@@ -0,0 +1,14 @@
1
+ ---
2
+ id: labelled-metrics
3
+ name: Labelled metrics
4
+ complexity: 0
5
+ components: [evaluation]
6
+ applies_when: [output_shape == classification, output_shape == ranking, output_shape == decision]
7
+ avoid_when: [output_shape == freeform, output_shape == structured]
8
+ evidence: {case_ids: [churn-scoring], confidence: high, last_verified: 2026-08-21}
9
+ ---
10
+ Precision, recall and their relatives against held-out labels.
11
+
12
+ Pick the metric from the cost of each error, not from convention. Where a false
13
+ negative costs a hundred times a false positive, accuracy is the wrong number
14
+ and will look fine while the system fails.
@@ -0,0 +1,26 @@
1
+ ---
2
+ id: llm-extraction
3
+ name: Model extraction
4
+ complexity: 2
5
+ components: [representation]
6
+ applies_when: [output_shape == structured]
7
+ avoid_when: [interpretability_required == true]
8
+ evidence: {case_ids: [structured-extraction], confidence: medium, last_verified: 2026-08-27}
9
+ ---
10
+ A model decoding raw records into the declared contract.
11
+
12
+ Split from the prompted-model approach deliberately, because the claim is
13
+ narrower than "use a model": this is a *representation* move, it exists only
14
+ where there is a contract to decode into, and freeform output has none. An
15
+ approach whose applicability differs by component is two approaches wearing
16
+ one name, and the seam always shows at the worst moment.
17
+
18
+ The opening move for extraction before anything has been measured -- the
19
+ deterministic path needs coverage nobody has counted and the cascade needs
20
+ calibration that does not exist yet. Behind the same Mapper interface the
21
+ deterministic path satisfies, so graduating when the numbers arrive is a
22
+ swap, not a redesign.
23
+
24
+ Avoided where interpretability is required: a mapping that cannot say why it
25
+ mapped is precisely what that requirement forbids, and the deterministic
26
+ path is the interpretable one.
@@ -0,0 +1,20 @@
1
+ ---
2
+ id: llm-scrubbing
3
+ name: Model-assisted scrubbing
4
+ complexity: 2
5
+ components: [redaction]
6
+ applies_when: [sensitivity_present == true]
7
+ avoid_when: [sensitivity_present == false, data_residency == cannot_leave]
8
+ evidence: {case_ids: [structured-extraction], confidence: low, last_verified: 2026-08-30}
9
+ ---
10
+ A model rewrites free text with the identifying entities removed, for the
11
+ case field-level masking cannot reach: a name living *inside* a narrative
12
+ field, not in a field of its own.
13
+
14
+ Never the first decision -- deterministic masking is simpler and wins where
15
+ the sensitive material is field-shaped, which is the common case and the
16
+ measurable one. Reached by override when the sample pairs show identifiers
17
+ inside prose, and carrying its own irony to manage: the scrubbing model sees
18
+ the unscrubbed text, so on a boundary engagement it must run inside -- and
19
+ where data cannot leave at all, the boundary already holds everything and
20
+ this approach is avoided outright.
@@ -0,0 +1,23 @@
1
+ ---
2
+ id: llm
3
+ name: Prompted model
4
+ complexity: 2
5
+ components: [reasoning]
6
+ applies_when: [output_shape == freeform, output_shape == structured]
7
+ avoid_when: [output_shape == classification, output_shape == decision]
8
+ evidence: {case_ids: [studio-style], confidence: medium, last_verified: 2026-08-21}
9
+ ---
10
+ A capable model, prompted, with no adaptation.
11
+
12
+ The right first move for open-ended generation, and the fastest thing to stand
13
+ up. Try it before fine-tuning: the gap it leaves is what tells you whether
14
+ adaptation is worth its cost.
15
+
16
+ The same holds for structured output, where the model decodes into a declared
17
+ schema. This is the standard opening move for extraction before anything has
18
+ been measured -- the cascade needs calibration that does not exist yet, and
19
+ the deterministic path needs coverage nobody has counted. Start here, measure,
20
+ then graduate.
21
+
22
+ Swapping the model rarely fixes a wrong answer -- it changes the tone of the
23
+ wrong answer. When quality is capped, look upstream at what the model was given.
@@ -0,0 +1,28 @@
1
+ ---
2
+ id: local-embedding
3
+ name: Local embeddings
4
+ complexity: 1
5
+ components: [embedding]
6
+ applies_when: [data_residency == cannot_leave, hosting == air-gapped, hosting == on-prem]
7
+ avoid_when: [operates_after_handover == nobody_yet and data_residency == may_leave]
8
+ evidence: {case_ids: [structured-extraction], confidence: high, last_verified: 2026-08-25}
9
+ ---
10
+ An embedding model running inside the boundary.
11
+
12
+ Chosen because something forbids the alternative rather than because it is
13
+ better. Small embedding models are cheap to run and unremarkable to operate,
14
+ which makes this a far lighter obligation than self-hosting a generation model
15
+ -- but it is still a model somebody has to keep running after the engagement
16
+ ends.
17
+
18
+ Ruled out where nobody is named to operate it. A model with no owner is a
19
+ liability handed over with a bow on it, and an embedding model whose host dies
20
+ takes the index with it.
21
+
22
+ The handover concern is stated precisely rather than broadly: with nobody
23
+ named to operate and data free to leave, the managed alternative is
24
+ strictly simpler and wins. But where data cannot leave, the plain
25
+ realization is an in-process library call whose operational burden is the
26
+ application's own -- the broad version of this avoid once treated a
27
+ library import like a GPU fleet, and stranded every engagement inside a
28
+ boundary.
@@ -0,0 +1,49 @@
1
+ ---
2
+ id: managed-api
3
+ name: Managed API
4
+ complexity: 0
5
+ components: [serving]
6
+ applies_when: [data_residency == may_leave]
7
+ avoid_when:
8
+ - data_residency == cannot_leave
9
+ - hosting == air-gapped
10
+ - hosting == on-prem
11
+ - human_waiting == no and corpus_size > 100000
12
+ - human_waiting == no and arrival_rate > 50000
13
+ - latency_budget_ms < 100
14
+ evidence: {case_ids: [studio-style], confidence: high, last_verified: 2026-08-21}
15
+ ---
16
+ Somebody else's endpoint, paid per token.
17
+
18
+ A p95 budget under a hundred milliseconds cannot be met across somebody
19
+ else's network: the round trip and their queue are spent before any work
20
+ happens. That is a physics objection, not a pricing one, which is why it is
21
+ a rule here rather than a note in the costing.
22
+
23
+ The volume objection is really about flow, not stock: fifty thousand
24
+ requests a day with nobody waiting is sustained work that rented GPUs do
25
+ for a fraction of per-token pricing, whatever the archive size says.
26
+
27
+ The cheapest way to be wrong cheaply: no infrastructure, no cold start, nothing
28
+ to operate. Sustained high-volume interactive traffic is where it stays cheapest
29
+ too, because self-hosting the same load means paying for redundancy and peak
30
+ headroom around the clock.
31
+
32
+ It stops being the cheapest option on high-volume work with nobody waiting:
33
+ per-token pricing at that scale runs several times what rented GPUs cost for
34
+ the same job, and the cold start nobody is waiting through costs nothing.
35
+
36
+ Sending data here is one-way. You cannot un-send it, which is a different
37
+ category of decision from an expensive one.
38
+
39
+ Provider prompt caching changes the arithmetic before any sizing does: reused
40
+ prompt prefixes bill at a fraction of the input rate, but only on exact token
41
+ match. That makes prompt hygiene a production concern, not an optimisation --
42
+ variable content (timestamps, user names) placed early in the prompt
43
+ invalidates every cached block after it, and rewriting history (summarising)
44
+ re-bills the whole prefix where trimming it in place stays byte-identical. A
45
+ semantic cache is a different animal: it returns stored responses on
46
+ similarity, skips the model entirely, and can return a confidently wrong
47
+ answer with a success status -- a sentence and its negation embed close
48
+ together. It is a retrieval system wearing a cache's name, and it needs the
49
+ same evaluation any retrieval gets.
@@ -0,0 +1,22 @@
1
+ ---
2
+ id: managed-embedding
3
+ name: Managed embeddings
4
+ complexity: 0
5
+ components: [embedding]
6
+ applies_when: [data_residency == may_leave]
7
+ avoid_when:
8
+ - data_residency == cannot_leave
9
+ - hosting == air-gapped
10
+ - hosting == on-prem
11
+ evidence: {case_ids: [studio-style], confidence: high, last_verified: 2026-08-25}
12
+ ---
13
+ A vendor endpoint. Nothing to host, nothing to keep warm, and generally better
14
+ quality per unit of effort than anything self-hosted at small scale.
15
+
16
+ Ruled out wherever the text may not leave, and for the reason people find
17
+ surprising: sending an embedding is sending the text. Vectors are recoverable
18
+ to their source, so this is not a way of anonymising anything on the way out.
19
+
20
+ One-way, like any vendor call. And expensive to reverse for a second reason --
21
+ changing embedding model means reindexing everything, so leaving is a
22
+ reindexing project rather than a configuration change.
@@ -0,0 +1,32 @@
1
+ ---
2
+ id: manual-runbook
3
+ name: Written steps
4
+ complexity: 2
5
+ components: [provisioning]
6
+ applies_when: [always]
7
+ avoid_when:
8
+ - existing_cluster == true
9
+ evidence: {case_ids: [structured-extraction], confidence: medium, last_verified: 2026-08-25}
10
+ ---
11
+ Steps somebody follows, written down.
12
+
13
+ The floor, and what nothing-known resolves to. Automating a deployment before
14
+ anyone has performed it once tends to automate a guess -- and a runbook that has
15
+ been followed successfully is the only honest input to a playbook worth writing.
16
+
17
+ Not a permanent answer. It is the rung that costs least to be wrong about, and
18
+ it graduates as soon as the environment is understood well enough that repeating
19
+ the steps is tedious rather than instructive.
20
+
21
+ Ruled out where the team already runs something. Handing a written procedure to
22
+ a shop with an existing tool is asking them to do by hand what they already
23
+ automate.
24
+
25
+ Complexity 2, not 0, and the number is the design: complexity orders by
26
+ cost of ownership, and a runbook is recurring human labour forever --
27
+ every automated tool that applies beats it on that measure, which is the
28
+ preference expressed without a single avoid rule. When the better tools
29
+ are blocked (an Ansible shop with an ephemeral environment, a Terraform
30
+ shop with no API), nothing avoids the runbook, and the floor holds.
31
+ Ephemeral by hand is painful and is said so here; painful is not the same
32
+ as impossible.
@@ -0,0 +1,19 @@
1
+ ---
2
+ id: model-planner
3
+ name: Model planner
4
+ complexity: 3
5
+ components: [planning]
6
+ applies_when: [output_shape == decision, recall_span == across_sessions]
7
+ avoid_when: [interpretability_required == true]
8
+ evidence: {case_ids: [route-planning], confidence: low, last_verified: 2026-08-21}
9
+ ---
10
+ The model decomposes the goal at run time and chooses what to do next.
11
+
12
+ This is the line worth drawing. Once the next step can depend on the last in a
13
+ way nobody enumerated, paths stop being testable and cost stops being bounded --
14
+ so crossing it obliges three things a fixed sequence never needed: a step cap, a
15
+ budget cap, and a critic before anything irreversible.
16
+
17
+ Ruled out where a decision must be explained. A plan invented at run time is
18
+ hard to defend afterwards, and "the model decided" is not a reason a regulator
19
+ accepts.