fde-framework 0.1.45__tar.gz → 0.1.46__tar.gz

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 (406) hide show
  1. {fde_framework-0.1.45 → fde_framework-0.1.46}/CHANGELOG.md +45 -0
  2. {fde_framework-0.1.45 → fde_framework-0.1.46}/PKG-INFO +48 -80
  3. {fde_framework-0.1.45 → fde_framework-0.1.46}/README.md +46 -79
  4. {fde_framework-0.1.45 → fde_framework-0.1.46}/pyproject.toml +2 -2
  5. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/cli.py +53 -6
  6. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/emit.py +16 -4
  7. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/factlog.py +15 -3
  8. fde_framework-0.1.46/src/fde/report.py +203 -0
  9. fde_framework-0.1.46/tests/test_assets.py +37 -0
  10. fde_framework-0.1.46/tests/test_report.py +80 -0
  11. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_sanitisation.py +9 -3
  12. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_stop.py +30 -0
  13. {fde_framework-0.1.45 → fde_framework-0.1.46}/.gitignore +0 -0
  14. {fde_framework-0.1.45 → fde_framework-0.1.46}/LICENSE +0 -0
  15. {fde_framework-0.1.45 → fde_framework-0.1.46}/examples/invoice-extraction/README.md +0 -0
  16. {fde_framework-0.1.45 → fde_framework-0.1.46}/examples/policy-qa/README.md +0 -0
  17. {fde_framework-0.1.45 → fde_framework-0.1.46}/examples/support-triage/README.md +0 -0
  18. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/ansible-playbook.md +0 -0
  19. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/assisted-deterministic.md +0 -0
  20. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/audit-only.md +0 -0
  21. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/boundary-and-audit.md +0 -0
  22. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/cascade.md +0 -0
  23. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/classical-ml.md +0 -0
  24. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/compose.md +0 -0
  25. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/decision-log.md +0 -0
  26. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/deterministic-masking.md +0 -0
  27. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/deterministic.md +0 -0
  28. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/direct-call.md +0 -0
  29. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/episodic-store.md +0 -0
  30. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/explainability-record.md +0 -0
  31. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/field-match.md +0 -0
  32. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/finetune.md +0 -0
  33. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/fixed-sequence.md +0 -0
  34. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/gitops.md +0 -0
  35. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/governed-tools.md +0 -0
  36. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/graph-expanded-retrieval.md +0 -0
  37. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/graph-retrieval.md +0 -0
  38. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/hybrid-search.md +0 -0
  39. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/judged.md +0 -0
  40. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/keyword-search.md +0 -0
  41. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/kubernetes-manifests.md +0 -0
  42. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/labelled-decision.md +0 -0
  43. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/labelled-metrics.md +0 -0
  44. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/llm-extraction.md +0 -0
  45. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/llm-scrubbing.md +0 -0
  46. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/llm.md +0 -0
  47. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/local-embedding.md +0 -0
  48. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/managed-api.md +0 -0
  49. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/managed-embedding.md +0 -0
  50. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/manual-runbook.md +0 -0
  51. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/model-planner.md +0 -0
  52. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/ocr-pipeline.md +0 -0
  53. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/optimisation-reasoning.md +0 -0
  54. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/optimisation.md +0 -0
  55. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/passthrough.md +0 -0
  56. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/reranked-retrieval.md +0 -0
  57. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/role-scoped-authority.md +0 -0
  58. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/segmentation.md +0 -0
  59. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/self-hosted.md +0 -0
  60. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/serverless-gpu.md +0 -0
  61. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/speech-transcription.md +0 -0
  62. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/structured-logs.md +0 -0
  63. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/systemd-unit.md +0 -0
  64. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/terraform-module.md +0 -0
  65. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/text-extraction.md +0 -0
  66. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/traced.md +0 -0
  67. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/vector-search.md +0 -0
  68. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/video-ingestion.md +0 -0
  69. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/windowed-ingestion.md +0 -0
  70. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/working-state.md +0 -0
  71. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/cases/churn-scoring.md +0 -0
  72. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/cases/route-planning.md +0 -0
  73. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/cases/structured-extraction.md +0 -0
  74. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/cases/studio-style.md +0 -0
  75. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/components/accountability.md +0 -0
  76. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/components/deployment.md +0 -0
  77. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/components/embedding.md +0 -0
  78. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/components/evaluation.md +0 -0
  79. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/components/governance.md +0 -0
  80. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/components/integration.md +0 -0
  81. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/components/memory.md +0 -0
  82. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/components/observability.md +0 -0
  83. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/components/perception.md +0 -0
  84. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/components/planning.md +0 -0
  85. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/components/provisioning.md +0 -0
  86. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/components/reasoning.md +0 -0
  87. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/components/redaction.md +0 -0
  88. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/components/representation.md +0 -0
  89. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/components/retrieval.md +0 -0
  90. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/components/serving.md +0 -0
  91. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/accelerator.md +0 -0
  92. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/access_model.md +0 -0
  93. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/arrival_rate.md +0 -0
  94. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/availability_target.md +0 -0
  95. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/cheap_path_coverage.md +0 -0
  96. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/confidence_calibrated.md +0 -0
  97. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/container_competence.md +0 -0
  98. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/corpus_churn.md +0 -0
  99. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/corpus_size.md +0 -0
  100. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/data_residency.md +0 -0
  101. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/environment_lifetime.md +0 -0
  102. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/existing_cluster.md +0 -0
  103. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/existing_iac_tool.md +0 -0
  104. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/external_systems.md +0 -0
  105. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/hosting.md +0 -0
  106. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/human_waiting.md +0 -0
  107. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/input_format.md +0 -0
  108. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/interpretability_required.md +0 -0
  109. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/labelled_count.md +0 -0
  110. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/latency_budget_ms.md +0 -0
  111. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/licence_posture.md +0 -0
  112. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/operates_after_handover.md +0 -0
  113. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/output_shape.md +0 -0
  114. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/provisioning_api.md +0 -0
  115. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/query_pattern.md +0 -0
  116. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/recall_span.md +0 -0
  117. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/sensitivity_present.md +0 -0
  118. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/interfaces/Generator.md +0 -0
  119. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/interfaces/Guard.md +0 -0
  120. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/interfaces/Mapper.md +0 -0
  121. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/interfaces/ModelServer.md +0 -0
  122. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/interfaces/Parser.md +0 -0
  123. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/interfaces/Planner.md +0 -0
  124. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/interfaces/Retriever.md +0 -0
  125. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/interfaces/Scorer.md +0 -0
  126. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/interfaces/Store.md +0 -0
  127. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/interfaces/ToolBoundary.md +0 -0
  128. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/interfaces/Tracer.md +0 -0
  129. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/locales/eu-gdpr.md +0 -0
  130. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/locales/in-dpdp.md +0 -0
  131. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/ansible-playbook.md +0 -0
  132. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/assisted-deterministic.md +0 -0
  133. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/audit-only.md +0 -0
  134. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/boundary-and-audit.md +0 -0
  135. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/cascade-reasoning.md +0 -0
  136. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/cascade-representation.md +0 -0
  137. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/cascade-retrieval.md +0 -0
  138. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/classical-ml-reasoning.md +0 -0
  139. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/classical-ml.md +0 -0
  140. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/compose.md +0 -0
  141. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/decision-log.md +0 -0
  142. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/deterministic-masking.md +0 -0
  143. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/deterministic.md +0 -0
  144. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/direct-call.md +0 -0
  145. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/episodic-store.md +0 -0
  146. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/explainability-record.md +0 -0
  147. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/field-match.md +0 -0
  148. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/finetune-representation.md +0 -0
  149. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/finetune.md +0 -0
  150. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/fixed-sequence.md +0 -0
  151. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/gitops.md +0 -0
  152. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/governed-tools.md +0 -0
  153. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/graph-expanded-retrieval.md +0 -0
  154. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/graph-retrieval.md +0 -0
  155. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/hybrid-search.md +0 -0
  156. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/judged.md +0 -0
  157. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/keyword-search.md +0 -0
  158. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/kubernetes-manifests.md +0 -0
  159. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/labelled-decision.md +0 -0
  160. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/labelled-metrics.md +0 -0
  161. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/llm-representation.md +0 -0
  162. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/llm-scrubbing.md +0 -0
  163. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/llm.md +0 -0
  164. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/local-embedding.md +0 -0
  165. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/managed-api.md +0 -0
  166. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/managed-embedding.md +0 -0
  167. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/manual-runbook.md +0 -0
  168. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/model-planner.md +0 -0
  169. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/ocr-pipeline.md +0 -0
  170. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/optimisation-reasoning.md +0 -0
  171. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/optimisation.md +0 -0
  172. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/passthrough.md +0 -0
  173. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/reranked-retrieval.md +0 -0
  174. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/role-scoped-authority.md +0 -0
  175. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/segmentation.md +0 -0
  176. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/self-hosted.md +0 -0
  177. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/serverless-gpu.md +0 -0
  178. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/speech-transcription.md +0 -0
  179. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/structured-logs.md +0 -0
  180. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/systemd-unit.md +0 -0
  181. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/terraform-module.md +0 -0
  182. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/text-extraction.md +0 -0
  183. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/traced.md +0 -0
  184. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/vector-search.md +0 -0
  185. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/video-ingestion.md +0 -0
  186. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/windowed-ingestion.md +0 -0
  187. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/working-state.md +0 -0
  188. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/langgraph.md +0 -0
  189. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/llamaindex.md +0 -0
  190. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/local-judge.md +0 -0
  191. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/mcp.md +0 -0
  192. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/ollama.md +0 -0
  193. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/openai-judge.md +0 -0
  194. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/opentelemetry.md +0 -0
  195. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/ortools.md +0 -0
  196. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/peft.md +0 -0
  197. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/pgvector.md +0 -0
  198. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/plain-python.md +0 -0
  199. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/qdrant.md +0 -0
  200. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/supermemory.md +0 -0
  201. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/tesseract.md +0 -0
  202. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/vllm.md +0 -0
  203. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/whisper.md +0 -0
  204. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/xgboost.md +0 -0
  205. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/accountability/decision-log.plain.py.j2 +0 -0
  206. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/accountability/explainability-record.plain.py.j2 +0 -0
  207. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/deployment/compose.plain.py.j2 +0 -0
  208. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/deployment/kubernetes-manifests.plain.py.j2 +0 -0
  209. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/deployment/systemd-unit.plain.py.j2 +0 -0
  210. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/embedding/local-embedding.plain.py.j2 +0 -0
  211. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/embedding/managed-embedding.plain.py.j2 +0 -0
  212. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/evaluation/field-match.plain.py.j2 +0 -0
  213. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/evaluation/judged.local-judge.py.j2 +0 -0
  214. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/evaluation/judged.openai-judge.py.j2 +0 -0
  215. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/evaluation/judged.plain.py.j2 +0 -0
  216. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/evaluation/labelled-metrics.plain.py.j2 +0 -0
  217. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/evaluation/labelled-metrics.xgboost.py.j2 +0 -0
  218. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/governance/audit-only.plain.py.j2 +0 -0
  219. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/governance/boundary-and-audit.plain.py.j2 +0 -0
  220. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/governance/role-scoped-authority.plain.py.j2 +0 -0
  221. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/integration/direct-call.plain.py.j2 +0 -0
  222. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/integration/governed-tools.mcp.py.j2 +0 -0
  223. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/integration/governed-tools.plain.py.j2 +0 -0
  224. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/memory/episodic-store.pgvector.py.j2 +0 -0
  225. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/memory/episodic-store.plain.py.j2 +0 -0
  226. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/memory/episodic-store.supermemory.py.j2 +0 -0
  227. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/memory/working-state.plain.py.j2 +0 -0
  228. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/observability/structured-logs.plain.py.j2 +0 -0
  229. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/observability/traced.opentelemetry.py.j2 +0 -0
  230. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/observability/traced.plain.py.j2 +0 -0
  231. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/perception/ocr-pipeline.plain.py.j2 +0 -0
  232. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/perception/ocr-pipeline.tesseract.py.j2 +0 -0
  233. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/perception/passthrough.plain.py.j2 +0 -0
  234. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/perception/speech-transcription.plain.py.j2 +0 -0
  235. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/perception/speech-transcription.whisper.py.j2 +0 -0
  236. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/perception/text-extraction.plain.py.j2 +0 -0
  237. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/perception/video-ingestion.plain.py.j2 +0 -0
  238. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/perception/windowed-ingestion.plain.py.j2 +0 -0
  239. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/planning/fixed-sequence.plain.py.j2 +0 -0
  240. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/planning/model-planner.langgraph.py.j2 +0 -0
  241. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/planning/model-planner.plain.py.j2 +0 -0
  242. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/planning/optimisation.ortools.py.j2 +0 -0
  243. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/planning/optimisation.plain.py.j2 +0 -0
  244. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/provisioning/ansible-playbook.plain.py.j2 +0 -0
  245. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/provisioning/gitops.plain.py.j2 +0 -0
  246. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/provisioning/manual-runbook.plain.py.j2 +0 -0
  247. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/provisioning/terraform-module.plain.py.j2 +0 -0
  248. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/reasoning/cascade.plain.py.j2 +0 -0
  249. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/reasoning/classical-ml.plain.py.j2 +0 -0
  250. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/reasoning/classical-ml.xgboost.py.j2 +0 -0
  251. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/reasoning/finetune.plain.py.j2 +0 -0
  252. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/reasoning/labelled-decision.plain.py.j2 +0 -0
  253. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/reasoning/llm.plain.py.j2 +0 -0
  254. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/reasoning/optimisation.ortools.py.j2 +0 -0
  255. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/reasoning/optimisation.plain.py.j2 +0 -0
  256. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/redaction/deterministic-masking.plain.py.j2 +0 -0
  257. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/redaction/llm-scrubbing.plain.py.j2 +0 -0
  258. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/representation/assisted.plain.py.j2 +0 -0
  259. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/representation/cascade.plain.py.j2 +0 -0
  260. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/representation/classical-ml.plain.py.j2 +0 -0
  261. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/representation/classical-ml.xgboost.py.j2 +0 -0
  262. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/representation/deterministic.plain.py.j2 +0 -0
  263. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/representation/finetune.plain.py.j2 +0 -0
  264. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/representation/llm.plain.py.j2 +0 -0
  265. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/representation/segmentation.plain.py.j2 +0 -0
  266. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/retrieval/cascade.plain.py.j2 +0 -0
  267. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/retrieval/graph-expanded-retrieval.pgvector.py.j2 +0 -0
  268. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/retrieval/graph-expanded-retrieval.plain.py.j2 +0 -0
  269. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/retrieval/graph-expanded-retrieval.qdrant.py.j2 +0 -0
  270. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/retrieval/graph-retrieval.pgvector.py.j2 +0 -0
  271. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/retrieval/graph-retrieval.plain.py.j2 +0 -0
  272. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/retrieval/graph-retrieval.qdrant.py.j2 +0 -0
  273. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/retrieval/hybrid-search.plain.py.j2 +0 -0
  274. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/retrieval/keyword-search.plain.py.j2 +0 -0
  275. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/retrieval/reranked-retrieval.plain.py.j2 +0 -0
  276. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/retrieval/vector-search.llamaindex.py.j2 +0 -0
  277. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/retrieval/vector-search.pgvector.py.j2 +0 -0
  278. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/retrieval/vector-search.plain.py.j2 +0 -0
  279. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/retrieval/vector-search.qdrant.py.j2 +0 -0
  280. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/serving/managed-api.plain.py.j2 +0 -0
  281. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/serving/self-hosted.ollama.py.j2 +0 -0
  282. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/serving/self-hosted.plain.py.j2 +0 -0
  283. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/serving/self-hosted.vllm.py.j2 +0 -0
  284. {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/serving/serverless-gpu.plain.py.j2 +0 -0
  285. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/__init__.py +0 -0
  286. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/architect.py +0 -0
  287. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/bench.py +0 -0
  288. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/costing.py +0 -0
  289. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/debt.py +0 -0
  290. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/decide.py +0 -0
  291. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/decompose.py +0 -0
  292. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/deploy.py +0 -0
  293. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/drift.py +0 -0
  294. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/evolution.py +0 -0
  295. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/experiment.py +0 -0
  296. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/forecast.py +0 -0
  297. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/gates.py +0 -0
  298. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/graph.py +0 -0
  299. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/history.py +0 -0
  300. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/impact.py +0 -0
  301. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/implement.py +0 -0
  302. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/importer.py +0 -0
  303. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/intake/__init__.py +0 -0
  304. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/intake/answers.py +0 -0
  305. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/intake/documents.py +0 -0
  306. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/intake/interview.py +0 -0
  307. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/intake/llm_reader.py +0 -0
  308. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/intake/prose.py +0 -0
  309. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/intake/samples.py +0 -0
  310. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/lifecycle.py +0 -0
  311. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/mcp_server.py +0 -0
  312. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/models/__init__.py +0 -0
  313. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/models/base.py +0 -0
  314. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/models/fact.py +0 -0
  315. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/models/profile.py +0 -0
  316. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/models/respondent.py +0 -0
  317. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/models/schema.py +0 -0
  318. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/moves.py +0 -0
  319. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/ops.py +0 -0
  320. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/predicate.py +0 -0
  321. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/realization.py +0 -0
  322. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/registry.py +0 -0
  323. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/sandbox.py +0 -0
  324. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/scan.py +0 -0
  325. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/scorecard.py +0 -0
  326. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/space.py +0 -0
  327. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/stakeholders.py +0 -0
  328. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/stop.py +0 -0
  329. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/training.py +0 -0
  330. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/value.py +0 -0
  331. {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/workflow.py +0 -0
  332. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/__init__.py +0 -0
  333. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/conftest.py +0 -0
  334. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/models/__init__.py +0 -0
  335. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/models/test_profile.py +0 -0
  336. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_acceptance.py +0 -0
  337. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_access_and_sensitivity.py +0 -0
  338. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_answers.py +0 -0
  339. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_audit_fixes.py +0 -0
  340. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_bench.py +0 -0
  341. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_build_receipt.py +0 -0
  342. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_cascade.py +0 -0
  343. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_cli_engagement.py +0 -0
  344. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_cli_evolution.py +0 -0
  345. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_cli_gates.py +0 -0
  346. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_cli_intake.py +0 -0
  347. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_cli_kb.py +0 -0
  348. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_cli_robustness.py +0 -0
  349. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_cli_samples.py +0 -0
  350. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_costing.py +0 -0
  351. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_coverage.py +0 -0
  352. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_dead_zones.py +0 -0
  353. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_debt.py +0 -0
  354. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_decide.py +0 -0
  355. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_decompose.py +0 -0
  356. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_deploy.py +0 -0
  357. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_documents.py +0 -0
  358. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_drift.py +0 -0
  359. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_embedding.py +0 -0
  360. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_emit.py +0 -0
  361. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_evolution.py +0 -0
  362. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_example_transcript.py +0 -0
  363. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_experiment.py +0 -0
  364. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_factlog.py +0 -0
  365. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_finetune.py +0 -0
  366. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_finetune_real.py +0 -0
  367. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_forecast.py +0 -0
  368. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_gates.py +0 -0
  369. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_history.py +0 -0
  370. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_impact.py +0 -0
  371. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_implement.py +0 -0
  372. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_importer.py +0 -0
  373. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_interview.py +0 -0
  374. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_lifecycle.py +0 -0
  375. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_llm_reader.py +0 -0
  376. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_locales.py +0 -0
  377. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_mcp.py +0 -0
  378. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_mcp_stdio.py +0 -0
  379. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_memory_retrieval.py +0 -0
  380. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_more_templates.py +0 -0
  381. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_moves.py +0 -0
  382. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_multimodal.py +0 -0
  383. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_next.py +0 -0
  384. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_ops.py +0 -0
  385. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_outcome_contract.py +0 -0
  386. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_package.py +0 -0
  387. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_prose.py +0 -0
  388. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_realization.py +0 -0
  389. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_registry.py +0 -0
  390. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_release_consistency.py +0 -0
  391. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_remaining.py +0 -0
  392. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_retrieval_eval.py +0 -0
  393. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_reversibility.py +0 -0
  394. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_samples.py +0 -0
  395. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_sandbox.py +0 -0
  396. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_scan.py +0 -0
  397. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_schema.py +0 -0
  398. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_scorecard.py +0 -0
  399. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_serving.py +0 -0
  400. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_shipped_registry.py +0 -0
  401. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_space.py +0 -0
  402. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_stack_swap.py +0 -0
  403. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_stakeholders.py +0 -0
  404. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_supermemory.py +0 -0
  405. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_templates.py +0 -0
  406. {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_value.py +0 -0
@@ -5,6 +5,51 @@ the project is pre-release, so everything sits under 0.1.0 until the first tag.
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [0.1.46] — 2026-10-12
9
+
10
+ Three readings in a row asked for the same thing before anything else:
11
+ the decision, as a document a person who never sees the terminal can act
12
+ on. Writing it exposed one more place the record was reading the wrong
13
+ build.
14
+
15
+ - **`fde report`: the decision brief.** One Markdown file read off the
16
+ record, before any build is authorised: the problem as the client
17
+ stated it, where the engagement stands, what the record knows and who
18
+ said it, the outcome contract, the design with its reasons and rejected
19
+ alternatives, what it rests on and what was waived, the decision debt,
20
+ the stop conditions judged against what has been measured, who has been
21
+ heard, and the next decision. The design and the risks are rendered by
22
+ the same functions a build uses for ARCHITECTURE.md and RISKS.md, so
23
+ the brief and a later build say the same thing; the readings that are
24
+ commands are quoted as the terminal prints them, so the brief cannot
25
+ say more than the commands do. Nothing in it is estimated. `--today`
26
+ makes it reproducible to the byte.
27
+ - **The deployment names its build, and the record reads that build.**
28
+ The banking record, read without `--project`, stood at *stopped*: its
29
+ last-built marker named the emitted project, whose card is 0.879 on
30
+ the answered, while the implemented copy beside it -- the one actually
31
+ served, 0.902 -- passed. `fde deployed --project` records which build
32
+ was deployed, and every command that reads a project by default reads
33
+ the deployed one, then the last one built. Refused for a directory that
34
+ is not an emitted project.
35
+ - **The README's front page answers three questions.** What this is, why
36
+ use it, how fast a result shows. The audit-pass story and the
37
+ thirty-line list of what every emission is held to moved verbatim to
38
+ `HISTORY.md`; the four demos are one line each, saying what each
39
+ proved. The claim ladder and the demo table are unchanged.
40
+ - **The pictures say what the code says.** The README banner and the
41
+ social-preview card had carried "seven gates" since before the eighth
42
+ gate shipped in 0.1.30, drawn once by hand; a fourteenth outside
43
+ reading found the banner contradicting the README it headed. They are
44
+ now drawn by `assets/brand.py` from the gate count the gates module
45
+ reports, each image carries its sentence in a PNG text chunk, and a
46
+ test holds the pictures to the code. The site's image alt text said the
47
+ same; corrected.
48
+ - The demo table says what *Stage* is: the record's lifecycle stage,
49
+ computed from evidence, so `production` on the banking row means
50
+ deployed, attested and journalled -- on a laptop, as the record says --
51
+ not production reliability, which the claim ladder keeps unverified.
52
+
8
53
  ## [0.1.45] — 2026-10-11
9
54
 
10
55
  A twelfth outside reading, and a coding agent driving the server for the
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: fde-framework
3
- Version: 0.1.45
3
+ Version: 0.1.46
4
4
  Summary: The decision before the AI build: evidence in, an architecture with receipts out, a scored build or a stop. For Forward Deployed Engineers and anyone deciding whether an AI system should exist.
5
5
  Project-URL: Homepage, https://github.com/atulkapoor/fde-framework
6
6
  Project-URL: Documentation, https://atulkapoor.github.io/fde-framework/
@@ -31,6 +31,7 @@ Requires-Dist: pypdf>=4; extra == 'all'
31
31
  Requires-Dist: python-docx>=1; extra == 'all'
32
32
  Provides-Extra: dev
33
33
  Requires-Dist: mcp<3,>=2; extra == 'dev'
34
+ Requires-Dist: pillow>=10; extra == 'dev'
34
35
  Requires-Dist: pytest>=8; extra == 'dev'
35
36
  Requires-Dist: ruff>=0.6; extra == 'dev'
36
37
  Provides-Extra: documents
@@ -89,6 +90,7 @@ pip install fde-framework
89
90
  fde start acme --statement "Extract fields from supplier invoices."
90
91
  fde ask acme --role admin # role-scoped discovery interview
91
92
  fde architect acme # topology + chosen approaches (rationale lands in ARCHITECTURE.md)
93
+ fde report acme # the decision brief, for whoever has to act on it and is not here
92
94
  fde build acme --out project # refuses: eight gates guard the build
93
95
  # ...verify data access, capture the baseline, name the eval owner (each gate prints its remedy), then:
94
96
  fde build acme --out project # code + evals + deploy assets + runbook
@@ -241,7 +243,7 @@ ladder, so nothing here can be over-read:
241
243
 
242
244
  | Claim | Status | The evidence, and where it stops |
243
245
  |---|---|---|
244
- | The framework is implemented | verified | 1,316 tests on three Pythons in CI; lint clean; every audit finding pinned as a check before it was fixed; every release installed from the published wheel into a fresh interpreter and walked through the first five minutes |
246
+ | The framework is implemented | verified | 1,321 tests on three Pythons in CI; lint clean; every audit finding pinned as a check before it was fixed; every release installed from the published wheel into a fresh interpreter and walked through the first five minutes |
245
247
  | A build is reproducible | verified | byte-identical rebuild pinned by test; each public demo carries a Reproduce section and its digests |
246
248
  | The decisions generalise | partial | four shapes (extraction, freeform QA, a labelled decision, seventy-seven-way routing) on real data; one industry set; `fde kb sweep` names the shapes nothing serves |
247
249
  | The deliverable is production-reliable | unverified | no production engagement; the banking operating loop ran on a laptop and its record says so |
@@ -251,54 +253,30 @@ ladder, so nothing here can be over-read:
251
253
 
252
254
  **Demonstrated**: four complete engagements have run end to end on real
253
255
  data, all public with every refusal preserved.
254
- [fde-demo-receipts](https://github.com/atulkapoor/fde-demo-receipts) —
255
- 626 scanned receipts through gates, build, and an agent-driven implement
256
- loop (`fde implement`, graded against held-out cases the agent never sees)
257
- whose holdout refused an overfit implementation and whose measured plateau
258
- flipped the design from rules to a model, reason on the record.
259
- [fde-demo-complaints](https://github.com/atulkapoor/fde-demo-complaints) —
260
- 2,034 real consumer complaints through the decision shape: the exam
261
- refused ambiguous ground truth before it existed, the agent posture was
262
- decided from the facts, and the loop finished **green with the holdout
263
- passing** — the framework's first.
264
- [fde-demo-rfc-qa](https://github.com/atulkapoor/fde-demo-rfc-qa) —
265
- freeform QA over 58 real RFCs: 100% recall@10 on real queries, a green
266
- loop, and then the calibration gate **refusing its own judge** exactly as
267
- the prediction published beforehand said it would (73.7% agreement,
268
- refused; the judge's 89.5% was 26 points of flattery over the hand-graded
269
- 63.2%). Six of this framework's releases (0.1.6–0.1.11) shipped from what
270
- these runs found -- and after five independent audit passes reshaped the
271
- emitter (0.1.17–0.1.21), the complaints engagement was built and implemented
272
- again on 0.1.21: green in round 2, holdout 76.7% against the original's
273
- 63.3%, the run committed beside the original for comparison. A sixth pass,
274
- widened to the exam, the components and the fine-tuning path, signed off
275
- the freeform shape with conditions and refused the decision shape for
276
- reasons that were the generator's; 0.1.22 answered each as a check first.
277
- A seventh pass found those checks holding and the shape-specific work
278
- stopping short -- a mis-specified baseline, an in-sample exam, a training
279
- recipe that trained unshuffled on a prompt it never served -- and 0.1.23
280
- answered again the same way. 0.1.24 then ran the fine-tuning recipe for
281
- real on a small base model: the adapter learned the house style on cases
282
- it never saw, and the six defects that run exposed in the harness, the
283
- serving path and the comparison are fixed and pinned. An eighth pass gave
284
- the decision shape its first sign-off, with conditions, and 0.1.25 met
285
- them: probes on typical cases, label phrases rather than words, a merge
286
- path that trains, a comparison that says what it can claim. A ninth pass
287
- read the first industry run and the scorecard that measured it, and found
288
- the card measuring self-consistency rather than fitness; 0.1.27 gave it
289
- fitness rows -- the generalisation gap, an external exam a memoriser cannot
290
- pass, the engagement's own error-rate bar -- and gave the routed decision
291
- an abstain path and a reason on every answer.
292
- [fde-demo-banking](https://github.com/atulkapoor/fde-demo-banking) —
293
- an industry use case: support intent routing for a retail bank over
294
- 13,083 real messages and seventy-seven queues (Banking77). The framework's
295
- own reading of a seventy-seven-way decision, its brief parser, its label
296
- rule and one governance template each failed on it and were fixed before
297
- a number was quoted; the finished deliverable is an assist-mode router
298
- that abstains and says why, at 90.2% on what it routes with 18% handed to
299
- a person, scored on a 3,036-case holdout and the vendor's own test split,
300
- with `fde scorecard` saying which rows measure fitness and which measure
301
- self-consistency.
256
+
257
+ - [fde-demo-receipts](https://github.com/atulkapoor/fde-demo-receipts) --
258
+ 626 scanned receipts: the holdout refused an overfit implementation, and
259
+ a measured plateau flipped the design from rules to a model, reason on
260
+ the record.
261
+ - [fde-demo-complaints](https://github.com/atulkapoor/fde-demo-complaints) --
262
+ 2,034 real consumer complaints through the decision shape: the exam
263
+ refused ambiguous ground truth before it existed, and the loop finished
264
+ **green with the holdout passing**, the framework's first.
265
+ - [fde-demo-rfc-qa](https://github.com/atulkapoor/fde-demo-rfc-qa) --
266
+ freeform QA over 58 real RFCs: 100% recall@10 on real queries, then the
267
+ calibration gate **refusing its own judge** exactly as the prediction
268
+ published beforehand said it would (73.7% agreement, refused; the
269
+ judge's 89.5% was 26 points of flattery over the hand-graded 63.2%).
270
+ - [fde-demo-banking](https://github.com/atulkapoor/fde-demo-banking) --
271
+ an industry use case: support intent routing for a retail bank over
272
+ 13,083 real messages and seventy-seven queues. The finished deliverable
273
+ is an assist-mode router that abstains and says why, at 90.2% on what
274
+ it routes with 18% handed to a person, scored on a 3,036-case holdout
275
+ and the vendor's own test split.
276
+
277
+ Fourteen outside readings have shaped the releases since, each finding
278
+ pinned as a check before it was fixed; the story, pass by pass, is in
279
+ [`HISTORY.md`](https://github.com/atulkapoor/fde-framework/blob/main/HISTORY.md).
302
280
 
303
281
  **Built**: the pipeline exists end to end — intake (prose, documents, sample
304
282
  pairs, role-scoped interview, hardware scan) → fact log with provenance →
@@ -344,6 +322,13 @@ drill).
344
322
  | rfc-qa | prototype | 16/23 | 30.0% on 10 | 30.0% | -- |
345
323
  | banking | production (a laptop, attested as such; stopped once by its own stop condition, cleared at the shipped 1.0-nat margin) | 23/25; does not beat the bank's baseline, on coverage | 73.8% on 3,036, abstaining 18.2% | 90.2% | 71.6% on 3,079 |
346
324
 
325
+ *Stage* is the record's lifecycle stage, computed from its evidence by
326
+ `fde stage`. `production` means the build was deployed and attested by
327
+ name and the field has been journalled through it -- here on a laptop, as
328
+ the record says -- not that production reliability is proven; the claim
329
+ ladder above keeps that unverified until a client's production says
330
+ otherwise.
331
+
347
332
  ## Two rules
348
333
 
349
334
  Every intake surface — prose, interviews, scans, sample pairs, the client's
@@ -481,31 +466,12 @@ project/
481
466
 
482
467
  Emitted quality is a pinned property, not a promise: the framework's own
483
468
  test suite emits projects across representative architecture shapes and
484
- holds every emission to the operational contract — every environment
485
- variable the code reads is documented, everything the systemd unit demands
486
- is created by a shipped installer, CI has a lane that goes green without a
487
- model, the smoke test passes on a fresh emission, the code is lint-clean,
488
- the payload path composes end to end and refuses garbage at the door, a
489
- caller cannot forge a result, a hostile document or a long query costs
490
- milliseconds, the journal stays one JSON line per event under threads, an
491
- error closes its connection, a bad corpus file is skipped and counted, the
492
- boundary refuses an endpoint outside it, the ledger survives a restart and
493
- a torn line, a stopword cannot cite a document and a one-document corpus
494
- still answers, compaction cannot drop a live key, every eval entry point
495
- honours the boundary, an oversized corpus refuses the boot with one line,
496
- readiness degrades rather than denies on a stray file, and the service
497
- carries a request id on every answer, a truncated query is never a silent
498
- miss, two processes cannot both reserve one key, a decision read off
499
- labelled text ships a fitted classifier that refuses to serve a constant,
500
- refuses an exam that changed since the build, beats the majority on the
501
- holdout and says which of its scores are in-sample, the exam's probes and
502
- edges come from cases the baseline was not fitted on and each steering
503
- probe says what it steers toward, an uncalibrated judge is red until asked
504
- for by name, a fact learned from a person is marked asserted rather than
505
- established, and a fine-tuning decision ships a recipe that trains on the
506
- prompt it serves -- and the deliverable ships its own edge tests, which
507
- its CI runs. Eight independent audit passes took it from "every request
508
- 500s" to a sign-off with conditions on the decision shape. A quality finding lands there as a check before
469
+ holds every emission to the operational contract, from every environment
470
+ variable the code reads being documented to a classifier that refuses to
471
+ serve a constant; the full list of what is held, and the audit passes that
472
+ put each check there, is in
473
+ [`HISTORY.md`](https://github.com/atulkapoor/fde-framework/blob/main/HISTORY.md).
474
+ A quality finding lands there as a check before
509
475
  it lands anywhere as a fix ([`tests/test_acceptance.py`](tests/test_acceptance.py),
510
476
  [`tests/test_finetune.py`](tests/test_finetune.py)). And the claim is
511
477
  measurable per build: `fde scorecard <project> --holdout <file> --external
@@ -538,9 +504,10 @@ declared by the tool.
538
504
  the holdout row, hours and money from the recorded baseline, build and run
539
505
  costs from the caller, payback, and a Wilson interval on the accuracy.
540
506
  Every line says what it rests on, so the number is argued row by row.
541
- - **`fde deployed`** and **`fde outcome`** are attestations: where it runs and
542
- who put it there; adoption, time to first value, whatever the client
543
- measured. **`fde outcomes`** prints what the record shows without anyone's
507
+ - **`fde deployed`** and **`fde outcome`** are attestations: where it runs,
508
+ who put it there and which build it is (`--project`, which every command
509
+ that reads a project by default then reads); adoption, time to first
510
+ value, whatever the client measured. **`fde outcomes`** prints what the record shows without anyone's
544
511
  opinion -- transitions, days to pilot, loop rounds, reversals, incidents.
545
512
  - **`fde stakeholders`** maps the engagement's people as the record shows
546
513
  them: which of the five roles has been heard (every session carries the
@@ -656,7 +623,7 @@ fde implement project # drive a coding agent until it's green
656
623
  fde scorecard project --holdout engagements/acme/artifacts/holdout.jsonl # measure it
657
624
 
658
625
  fde stage acme --project project # where it stands, computed off the record
659
- fde deployed acme --note "runs in the client VPC; platform team put it there"
626
+ fde deployed acme --note "runs in the client VPC; platform team put it there" --project project
660
627
  fde drift acme --journal service.log --project project # the field against the exam
661
628
  fde incident acme close inc-001 --note "holdout re-scored; pairs redrawn"
662
629
  fde outcome acme --metric adoption=0.62 --note "support lead's dashboard, week 3"
@@ -711,12 +678,13 @@ the same receipts the emitted `ARCHITECTURE.md` prints.
711
678
  | `fde reuse <eng> <stack>` | record what the client already operates, so reuse can beat adoption |
712
679
  | `fde locale <eng> eu-gdpr` | jurisdiction pack: presets plus obligations emitted as COMPLIANCE.md |
713
680
  | `fde architect <eng>` | the design, rationale and rejections |
681
+ | `fde report <eng> [--out brief.md]` | the decision brief: the problem as stated, the stage, what is known and who said it, the outcome contract, the design with its reasons and rejections, what it rests on, the debt, the stop conditions, the next decision -- one Markdown file, before any build |
714
682
  | `fde build <eng> --out project` | emit; refuses while gates block |
715
683
  | `fde implement project/` | drive a coding agent until the emitted evals pass, inside guardrails |
716
684
  | `fde scorecard project/ --holdout <file>` | measure production grade: every property the deliverable can prove, with the number, in `SCORECARD.md` |
717
685
  | `fde scorecard project/ --holdout <file> --coverage-floor 0.97 --max-gap 0.08` | the engagement's own bars: the share the system must answer for the baseline row to hold (default: 1 minus the baseline's exception rate), and its limit on the golden-to-holdout gap (protocol default 20%) |
718
686
  | `fde stage <eng>` | where the engagement stands, computed from the record; transitions appended to `lifecycle.jsonl` (`--no-record` to look without appending) |
719
- | `fde deployed <eng> --note "..."` | attest the deployment: where it runs and who put it there |
687
+ | `fde deployed <eng> --note "..." [--project <dir>]` | attest the deployment: where it runs, who put it there, which build |
720
688
  | `fde drift <eng> --journal <log>` | the field against the exam: abstention, mix, errors, margins; opens an incident and exits 1 when it moved |
721
689
  | `fde incident <eng> list \| close <id> --note "..."` | incidents on the record; an open one holds the stage at pilot |
722
690
  | `fde outcome <eng> --metric adoption=0.62` / `fde outcomes <eng>` | outcomes measured in the field; what the record shows without opinion |
@@ -45,6 +45,7 @@ pip install fde-framework
45
45
  fde start acme --statement "Extract fields from supplier invoices."
46
46
  fde ask acme --role admin # role-scoped discovery interview
47
47
  fde architect acme # topology + chosen approaches (rationale lands in ARCHITECTURE.md)
48
+ fde report acme # the decision brief, for whoever has to act on it and is not here
48
49
  fde build acme --out project # refuses: eight gates guard the build
49
50
  # ...verify data access, capture the baseline, name the eval owner (each gate prints its remedy), then:
50
51
  fde build acme --out project # code + evals + deploy assets + runbook
@@ -197,7 +198,7 @@ ladder, so nothing here can be over-read:
197
198
 
198
199
  | Claim | Status | The evidence, and where it stops |
199
200
  |---|---|---|
200
- | The framework is implemented | verified | 1,316 tests on three Pythons in CI; lint clean; every audit finding pinned as a check before it was fixed; every release installed from the published wheel into a fresh interpreter and walked through the first five minutes |
201
+ | The framework is implemented | verified | 1,321 tests on three Pythons in CI; lint clean; every audit finding pinned as a check before it was fixed; every release installed from the published wheel into a fresh interpreter and walked through the first five minutes |
201
202
  | A build is reproducible | verified | byte-identical rebuild pinned by test; each public demo carries a Reproduce section and its digests |
202
203
  | The decisions generalise | partial | four shapes (extraction, freeform QA, a labelled decision, seventy-seven-way routing) on real data; one industry set; `fde kb sweep` names the shapes nothing serves |
203
204
  | The deliverable is production-reliable | unverified | no production engagement; the banking operating loop ran on a laptop and its record says so |
@@ -207,54 +208,30 @@ ladder, so nothing here can be over-read:
207
208
 
208
209
  **Demonstrated**: four complete engagements have run end to end on real
209
210
  data, all public with every refusal preserved.
210
- [fde-demo-receipts](https://github.com/atulkapoor/fde-demo-receipts) —
211
- 626 scanned receipts through gates, build, and an agent-driven implement
212
- loop (`fde implement`, graded against held-out cases the agent never sees)
213
- whose holdout refused an overfit implementation and whose measured plateau
214
- flipped the design from rules to a model, reason on the record.
215
- [fde-demo-complaints](https://github.com/atulkapoor/fde-demo-complaints) —
216
- 2,034 real consumer complaints through the decision shape: the exam
217
- refused ambiguous ground truth before it existed, the agent posture was
218
- decided from the facts, and the loop finished **green with the holdout
219
- passing** — the framework's first.
220
- [fde-demo-rfc-qa](https://github.com/atulkapoor/fde-demo-rfc-qa) —
221
- freeform QA over 58 real RFCs: 100% recall@10 on real queries, a green
222
- loop, and then the calibration gate **refusing its own judge** exactly as
223
- the prediction published beforehand said it would (73.7% agreement,
224
- refused; the judge's 89.5% was 26 points of flattery over the hand-graded
225
- 63.2%). Six of this framework's releases (0.1.6–0.1.11) shipped from what
226
- these runs found -- and after five independent audit passes reshaped the
227
- emitter (0.1.17–0.1.21), the complaints engagement was built and implemented
228
- again on 0.1.21: green in round 2, holdout 76.7% against the original's
229
- 63.3%, the run committed beside the original for comparison. A sixth pass,
230
- widened to the exam, the components and the fine-tuning path, signed off
231
- the freeform shape with conditions and refused the decision shape for
232
- reasons that were the generator's; 0.1.22 answered each as a check first.
233
- A seventh pass found those checks holding and the shape-specific work
234
- stopping short -- a mis-specified baseline, an in-sample exam, a training
235
- recipe that trained unshuffled on a prompt it never served -- and 0.1.23
236
- answered again the same way. 0.1.24 then ran the fine-tuning recipe for
237
- real on a small base model: the adapter learned the house style on cases
238
- it never saw, and the six defects that run exposed in the harness, the
239
- serving path and the comparison are fixed and pinned. An eighth pass gave
240
- the decision shape its first sign-off, with conditions, and 0.1.25 met
241
- them: probes on typical cases, label phrases rather than words, a merge
242
- path that trains, a comparison that says what it can claim. A ninth pass
243
- read the first industry run and the scorecard that measured it, and found
244
- the card measuring self-consistency rather than fitness; 0.1.27 gave it
245
- fitness rows -- the generalisation gap, an external exam a memoriser cannot
246
- pass, the engagement's own error-rate bar -- and gave the routed decision
247
- an abstain path and a reason on every answer.
248
- [fde-demo-banking](https://github.com/atulkapoor/fde-demo-banking) —
249
- an industry use case: support intent routing for a retail bank over
250
- 13,083 real messages and seventy-seven queues (Banking77). The framework's
251
- own reading of a seventy-seven-way decision, its brief parser, its label
252
- rule and one governance template each failed on it and were fixed before
253
- a number was quoted; the finished deliverable is an assist-mode router
254
- that abstains and says why, at 90.2% on what it routes with 18% handed to
255
- a person, scored on a 3,036-case holdout and the vendor's own test split,
256
- with `fde scorecard` saying which rows measure fitness and which measure
257
- self-consistency.
211
+
212
+ - [fde-demo-receipts](https://github.com/atulkapoor/fde-demo-receipts) --
213
+ 626 scanned receipts: the holdout refused an overfit implementation, and
214
+ a measured plateau flipped the design from rules to a model, reason on
215
+ the record.
216
+ - [fde-demo-complaints](https://github.com/atulkapoor/fde-demo-complaints) --
217
+ 2,034 real consumer complaints through the decision shape: the exam
218
+ refused ambiguous ground truth before it existed, and the loop finished
219
+ **green with the holdout passing**, the framework's first.
220
+ - [fde-demo-rfc-qa](https://github.com/atulkapoor/fde-demo-rfc-qa) --
221
+ freeform QA over 58 real RFCs: 100% recall@10 on real queries, then the
222
+ calibration gate **refusing its own judge** exactly as the prediction
223
+ published beforehand said it would (73.7% agreement, refused; the
224
+ judge's 89.5% was 26 points of flattery over the hand-graded 63.2%).
225
+ - [fde-demo-banking](https://github.com/atulkapoor/fde-demo-banking) --
226
+ an industry use case: support intent routing for a retail bank over
227
+ 13,083 real messages and seventy-seven queues. The finished deliverable
228
+ is an assist-mode router that abstains and says why, at 90.2% on what
229
+ it routes with 18% handed to a person, scored on a 3,036-case holdout
230
+ and the vendor's own test split.
231
+
232
+ Fourteen outside readings have shaped the releases since, each finding
233
+ pinned as a check before it was fixed; the story, pass by pass, is in
234
+ [`HISTORY.md`](https://github.com/atulkapoor/fde-framework/blob/main/HISTORY.md).
258
235
 
259
236
  **Built**: the pipeline exists end to end — intake (prose, documents, sample
260
237
  pairs, role-scoped interview, hardware scan) → fact log with provenance →
@@ -300,6 +277,13 @@ drill).
300
277
  | rfc-qa | prototype | 16/23 | 30.0% on 10 | 30.0% | -- |
301
278
  | banking | production (a laptop, attested as such; stopped once by its own stop condition, cleared at the shipped 1.0-nat margin) | 23/25; does not beat the bank's baseline, on coverage | 73.8% on 3,036, abstaining 18.2% | 90.2% | 71.6% on 3,079 |
302
279
 
280
+ *Stage* is the record's lifecycle stage, computed from its evidence by
281
+ `fde stage`. `production` means the build was deployed and attested by
282
+ name and the field has been journalled through it -- here on a laptop, as
283
+ the record says -- not that production reliability is proven; the claim
284
+ ladder above keeps that unverified until a client's production says
285
+ otherwise.
286
+
303
287
  ## Two rules
304
288
 
305
289
  Every intake surface — prose, interviews, scans, sample pairs, the client's
@@ -437,31 +421,12 @@ project/
437
421
 
438
422
  Emitted quality is a pinned property, not a promise: the framework's own
439
423
  test suite emits projects across representative architecture shapes and
440
- holds every emission to the operational contract — every environment
441
- variable the code reads is documented, everything the systemd unit demands
442
- is created by a shipped installer, CI has a lane that goes green without a
443
- model, the smoke test passes on a fresh emission, the code is lint-clean,
444
- the payload path composes end to end and refuses garbage at the door, a
445
- caller cannot forge a result, a hostile document or a long query costs
446
- milliseconds, the journal stays one JSON line per event under threads, an
447
- error closes its connection, a bad corpus file is skipped and counted, the
448
- boundary refuses an endpoint outside it, the ledger survives a restart and
449
- a torn line, a stopword cannot cite a document and a one-document corpus
450
- still answers, compaction cannot drop a live key, every eval entry point
451
- honours the boundary, an oversized corpus refuses the boot with one line,
452
- readiness degrades rather than denies on a stray file, and the service
453
- carries a request id on every answer, a truncated query is never a silent
454
- miss, two processes cannot both reserve one key, a decision read off
455
- labelled text ships a fitted classifier that refuses to serve a constant,
456
- refuses an exam that changed since the build, beats the majority on the
457
- holdout and says which of its scores are in-sample, the exam's probes and
458
- edges come from cases the baseline was not fitted on and each steering
459
- probe says what it steers toward, an uncalibrated judge is red until asked
460
- for by name, a fact learned from a person is marked asserted rather than
461
- established, and a fine-tuning decision ships a recipe that trains on the
462
- prompt it serves -- and the deliverable ships its own edge tests, which
463
- its CI runs. Eight independent audit passes took it from "every request
464
- 500s" to a sign-off with conditions on the decision shape. A quality finding lands there as a check before
424
+ holds every emission to the operational contract, from every environment
425
+ variable the code reads being documented to a classifier that refuses to
426
+ serve a constant; the full list of what is held, and the audit passes that
427
+ put each check there, is in
428
+ [`HISTORY.md`](https://github.com/atulkapoor/fde-framework/blob/main/HISTORY.md).
429
+ A quality finding lands there as a check before
465
430
  it lands anywhere as a fix ([`tests/test_acceptance.py`](tests/test_acceptance.py),
466
431
  [`tests/test_finetune.py`](tests/test_finetune.py)). And the claim is
467
432
  measurable per build: `fde scorecard <project> --holdout <file> --external
@@ -494,9 +459,10 @@ declared by the tool.
494
459
  the holdout row, hours and money from the recorded baseline, build and run
495
460
  costs from the caller, payback, and a Wilson interval on the accuracy.
496
461
  Every line says what it rests on, so the number is argued row by row.
497
- - **`fde deployed`** and **`fde outcome`** are attestations: where it runs and
498
- who put it there; adoption, time to first value, whatever the client
499
- measured. **`fde outcomes`** prints what the record shows without anyone's
462
+ - **`fde deployed`** and **`fde outcome`** are attestations: where it runs,
463
+ who put it there and which build it is (`--project`, which every command
464
+ that reads a project by default then reads); adoption, time to first
465
+ value, whatever the client measured. **`fde outcomes`** prints what the record shows without anyone's
500
466
  opinion -- transitions, days to pilot, loop rounds, reversals, incidents.
501
467
  - **`fde stakeholders`** maps the engagement's people as the record shows
502
468
  them: which of the five roles has been heard (every session carries the
@@ -612,7 +578,7 @@ fde implement project # drive a coding agent until it's green
612
578
  fde scorecard project --holdout engagements/acme/artifacts/holdout.jsonl # measure it
613
579
 
614
580
  fde stage acme --project project # where it stands, computed off the record
615
- fde deployed acme --note "runs in the client VPC; platform team put it there"
581
+ fde deployed acme --note "runs in the client VPC; platform team put it there" --project project
616
582
  fde drift acme --journal service.log --project project # the field against the exam
617
583
  fde incident acme close inc-001 --note "holdout re-scored; pairs redrawn"
618
584
  fde outcome acme --metric adoption=0.62 --note "support lead's dashboard, week 3"
@@ -667,12 +633,13 @@ the same receipts the emitted `ARCHITECTURE.md` prints.
667
633
  | `fde reuse <eng> <stack>` | record what the client already operates, so reuse can beat adoption |
668
634
  | `fde locale <eng> eu-gdpr` | jurisdiction pack: presets plus obligations emitted as COMPLIANCE.md |
669
635
  | `fde architect <eng>` | the design, rationale and rejections |
636
+ | `fde report <eng> [--out brief.md]` | the decision brief: the problem as stated, the stage, what is known and who said it, the outcome contract, the design with its reasons and rejections, what it rests on, the debt, the stop conditions, the next decision -- one Markdown file, before any build |
670
637
  | `fde build <eng> --out project` | emit; refuses while gates block |
671
638
  | `fde implement project/` | drive a coding agent until the emitted evals pass, inside guardrails |
672
639
  | `fde scorecard project/ --holdout <file>` | measure production grade: every property the deliverable can prove, with the number, in `SCORECARD.md` |
673
640
  | `fde scorecard project/ --holdout <file> --coverage-floor 0.97 --max-gap 0.08` | the engagement's own bars: the share the system must answer for the baseline row to hold (default: 1 minus the baseline's exception rate), and its limit on the golden-to-holdout gap (protocol default 20%) |
674
641
  | `fde stage <eng>` | where the engagement stands, computed from the record; transitions appended to `lifecycle.jsonl` (`--no-record` to look without appending) |
675
- | `fde deployed <eng> --note "..."` | attest the deployment: where it runs and who put it there |
642
+ | `fde deployed <eng> --note "..." [--project <dir>]` | attest the deployment: where it runs, who put it there, which build |
676
643
  | `fde drift <eng> --journal <log>` | the field against the exam: abstention, mix, errors, margins; opens an incident and exits 1 when it moved |
677
644
  | `fde incident <eng> list \| close <id> --note "..."` | incidents on the record; an open one holds the stage at pilot |
678
645
  | `fde outcome <eng> --metric adoption=0.62` / `fde outcomes <eng>` | outcomes measured in the field; what the record shows without opinion |
@@ -2,7 +2,7 @@
2
2
  # Distribution name matches the repository and stays unique on any index;
3
3
  # the import package and the CLI command remain the short `fde`.
4
4
  name = "fde-framework"
5
- version = "0.1.45"
5
+ version = "0.1.46"
6
6
  description = "The decision before the AI build: evidence in, an architecture with receipts out, a scored build or a stop. For Forward Deployed Engineers and anyone deciding whether an AI system should exist."
7
7
  readme = "README.md"
8
8
  license = {text = "Apache-2.0"}
@@ -32,7 +32,7 @@ dependencies = [
32
32
  ]
33
33
 
34
34
  [project.optional-dependencies]
35
- dev = ["pytest>=8", "ruff>=0.6", "mcp>=2,<3"]
35
+ dev = ["pytest>=8", "ruff>=0.6", "mcp>=2,<3", "pillow>=10"] # pillow draws assets/
36
36
  # Document readers are optional: plain-text intake needs nothing, and an
37
37
  # air-gapped install should not drag in what it will not use.
38
38
  documents = ["pypdf>=4", "python-docx>=1"]
@@ -1894,10 +1894,16 @@ def scan_cmd(
1894
1894
 
1895
1895
 
1896
1896
  def _project_of(engagement, project: Path | None) -> Path | None:
1897
- """The project a command should read: the one given, else the last
1898
- build recorded by fde build."""
1897
+ """The project a command should read: the one given, else the build the
1898
+ deployment attestation names, else the last build recorded by fde
1899
+ build. The banking record once read as stopped from its emitted build
1900
+ while the implemented copy beside it, the one actually served, passed
1901
+ its stop condition: the default followed the build, not the deployment."""
1899
1902
  if project is not None:
1900
1903
  return Path(project)
1904
+ deployed = engagement.deployed_project()
1905
+ if deployed and Path(deployed).exists():
1906
+ return Path(deployed)
1901
1907
  record = engagement.root / ".last-out"
1902
1908
  if record.exists():
1903
1909
  candidate = Path(record.read_text().strip())
@@ -1943,17 +1949,27 @@ def stage_cmd(
1943
1949
  def deployed_cmd(
1944
1950
  root: Annotated[Path, typer.Argument(help="The engagement directory.")],
1945
1951
  note: Annotated[str, typer.Option(help="Where it runs and who put it there.")],
1952
+ project: Annotated[Path | None, typer.Option(
1953
+ "--project", help="The build that was deployed. Every command that reads a "
1954
+ "project by default then reads this one, not the last one built."
1955
+ )] = None,
1946
1956
  today: Annotated[str, typer.Option(help="For the record; defaults to today.")] = "",
1947
1957
  by: Annotated[str, typer.Option(help="Who signs this: a name for the record.")] = "",
1948
1958
  ) -> None:
1949
- """Attest that the deliverable is deployed. The lifecycle's production
1950
- stage reads this; nothing infers it from a build."""
1959
+ """Attest that the deliverable is deployed, and which build it is. The
1960
+ lifecycle's production stage reads this; nothing infers it from a build."""
1951
1961
  engagement = _engagement(root)
1952
1962
  if not note.strip():
1953
1963
  typer.echo("a deployment attestation needs a note", err=True)
1954
1964
  raise typer.Exit(1)
1955
- engagement.record_deployed(note, today or date.today().isoformat(), by=by)
1956
- typer.echo("deployment recorded")
1965
+ if project is not None and not (project / "scorecard.json").exists() \
1966
+ and not (project / "evals").is_dir():
1967
+ typer.echo(f"{project}: not an emitted project (no evals/ and no scorecard.json)",
1968
+ err=True)
1969
+ raise typer.Exit(1)
1970
+ engagement.record_deployed(note, today or date.today().isoformat(), by=by,
1971
+ project=str(project) if project is not None else "")
1972
+ typer.echo("deployment recorded" + (f" for {project}" if project is not None else ""))
1957
1973
 
1958
1974
 
1959
1975
  @app.command("drift")
@@ -2431,6 +2447,37 @@ def mcp_cmd(
2431
2447
  raise typer.Exit(1) from exc
2432
2448
 
2433
2449
 
2450
+ @app.command("report")
2451
+ def report_cmd(
2452
+ root: Annotated[Path, typer.Argument(help="The engagement directory.")],
2453
+ out: Annotated[Path | None, typer.Option(
2454
+ "--out", help="Where to write the brief; default artifacts/REPORT.md in the engagement."
2455
+ )] = None,
2456
+ registry_root: Annotated[Path, typer.Option("--registry")] = DEFAULT_ROOT,
2457
+ today: Annotated[str, typer.Option(help="The date on the brief; defaults to today.")] = "",
2458
+ ) -> None:
2459
+ """Write the decision brief: the problem as stated, where the engagement
2460
+ stands, what the record knows and who said it, the outcome contract,
2461
+ the design with its reasons, what it rests on, the decision debt, the
2462
+ stop conditions, the next decision -- one Markdown file for the person
2463
+ who has to act on the decision and is not at this terminal. Works
2464
+ before any build is authorised; every figure is read off the record."""
2465
+ from fde.report import render_report
2466
+
2467
+ registry = _registry(registry_root)
2468
+ engagement = _engagement(root)
2469
+ # The commands the brief quotes run in-process and get the registry as
2470
+ # an absolute path, so the brief reads one corpus wherever it is run from.
2471
+ corpus = Path(registry_root)
2472
+ text = render_report(engagement, registry, corpus.resolve() if corpus.exists() else corpus,
2473
+ today=today)
2474
+ target = out or (engagement.root / "artifacts" / "REPORT.md")
2475
+ target.parent.mkdir(parents=True, exist_ok=True)
2476
+ target.write_text(text)
2477
+ sections = text.count("\n## ")
2478
+ typer.echo(f"wrote {target} ({sections} sections, {len(text.splitlines())} lines)")
2479
+
2480
+
2434
2481
  @app.command("debt")
2435
2482
  def debt_cmd(
2436
2483
  root: Annotated[Path, typer.Argument(help="The engagement directory.")],
@@ -139,13 +139,25 @@ def _write_risks(
139
139
  receiving the project could not tell that the baseline gate had been
140
140
  waived, let alone that the baseline file was then deleted.
141
141
  """
142
- flat = _flat
143
-
144
- undecided = architecture.decisions.undecided()
145
142
  scaffolds = sorted(
146
143
  p.stem for p in (out / "app" / "components").glob("*.py")
147
144
  if SCAFFOLD_MARK.split(" #")[0] in p.read_text()
148
145
  )
146
+ (out / "RISKS.md").write_text(
147
+ render_risks(waivers, overrides, architecture, registry, scaffolds=scaffolds))
148
+
149
+
150
+ def render_risks(
151
+ waivers, overrides, architecture: Architecture, registry: Registry | None = None,
152
+ scaffolds: list[str] | tuple[str, ...] = (),
153
+ ) -> str:
154
+ """The risk page as text: what a build would write to RISKS.md, which
155
+ `fde report` carries before any build exists. `scaffolds` names the
156
+ emitted modules that still raise; a brief written before emission has
157
+ none."""
158
+ flat = _flat
159
+
160
+ undecided = architecture.decisions.undecided()
149
161
  lines = ["# Risks accepted", ""]
150
162
  if not waivers and not overrides and not architecture.unrealizable and not undecided:
151
163
  lines += [
@@ -237,7 +249,7 @@ def _write_risks(
237
249
  for component, reason in sorted(architecture.unrealizable.items())
238
250
  ]
239
251
  lines.append("")
240
- (out / "RISKS.md").write_text("\n".join(lines) + "\n")
252
+ return "\n".join(lines) + "\n"
241
253
 
242
254
 
243
255
  # --- refusals ------------------------------------------------------------
@@ -207,13 +207,25 @@ class Engagement:
207
207
  state["data_access"] = _signed({"note": note, "at": at}, by)
208
208
  self._write_gate_state(state)
209
209
 
210
- def record_deployed(self, note: str, at: str, by: str = "") -> None:
210
+ def record_deployed(self, note: str, at: str, by: str = "", project: str = "") -> None:
211
211
  """The deployment, attested like data access: where it runs and who
212
- put it there. The lifecycle reads it; nothing else infers it."""
212
+ put it there, and which build it is. The lifecycle reads it; nothing
213
+ else infers it. Naming the build matters once implementation has
214
+ produced a second project directory beside the emitted one: every
215
+ command that reads a project by default then reads the deployed
216
+ one, not the last one built."""
213
217
  state = self._raw_gate_state()
214
- state["deployed"] = _signed({"note": note, "at": at}, by)
218
+ entry = {"note": note, "at": at}
219
+ if project:
220
+ entry["project"] = project
221
+ state["deployed"] = _signed(entry, by)
215
222
  self._write_gate_state(state)
216
223
 
224
+ def deployed_project(self) -> str | None:
225
+ """The build the deployment attestation names, if it names one."""
226
+ deployed = self._raw_gate_state().get("deployed")
227
+ return deployed.get("project") or None if isinstance(deployed, dict) else None
228
+
217
229
  def record_security_review(self, note: str, at: str, by: str = "") -> None:
218
230
  state = self._raw_gate_state()
219
231
  state["security_review"] = _signed({"note": note, "at": at}, by)