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.
- {fde_framework-0.1.45 → fde_framework-0.1.46}/CHANGELOG.md +45 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/PKG-INFO +48 -80
- {fde_framework-0.1.45 → fde_framework-0.1.46}/README.md +46 -79
- {fde_framework-0.1.45 → fde_framework-0.1.46}/pyproject.toml +2 -2
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/cli.py +53 -6
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/emit.py +16 -4
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/factlog.py +15 -3
- fde_framework-0.1.46/src/fde/report.py +203 -0
- fde_framework-0.1.46/tests/test_assets.py +37 -0
- fde_framework-0.1.46/tests/test_report.py +80 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_sanitisation.py +9 -3
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_stop.py +30 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/.gitignore +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/LICENSE +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/examples/invoice-extraction/README.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/examples/policy-qa/README.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/examples/support-triage/README.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/ansible-playbook.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/assisted-deterministic.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/audit-only.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/boundary-and-audit.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/cascade.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/classical-ml.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/compose.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/decision-log.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/deterministic-masking.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/deterministic.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/direct-call.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/episodic-store.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/explainability-record.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/field-match.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/finetune.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/fixed-sequence.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/gitops.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/governed-tools.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/graph-expanded-retrieval.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/graph-retrieval.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/hybrid-search.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/judged.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/keyword-search.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/kubernetes-manifests.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/labelled-decision.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/labelled-metrics.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/llm-extraction.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/llm-scrubbing.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/llm.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/local-embedding.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/managed-api.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/managed-embedding.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/manual-runbook.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/model-planner.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/ocr-pipeline.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/optimisation-reasoning.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/optimisation.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/passthrough.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/reranked-retrieval.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/role-scoped-authority.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/segmentation.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/self-hosted.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/serverless-gpu.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/speech-transcription.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/structured-logs.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/systemd-unit.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/terraform-module.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/text-extraction.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/traced.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/vector-search.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/video-ingestion.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/windowed-ingestion.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/approaches/working-state.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/cases/churn-scoring.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/cases/route-planning.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/cases/structured-extraction.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/cases/studio-style.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/components/accountability.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/components/deployment.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/components/embedding.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/components/evaluation.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/components/governance.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/components/integration.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/components/memory.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/components/observability.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/components/perception.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/components/planning.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/components/provisioning.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/components/reasoning.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/components/redaction.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/components/representation.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/components/retrieval.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/components/serving.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/accelerator.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/access_model.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/arrival_rate.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/availability_target.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/cheap_path_coverage.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/confidence_calibrated.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/container_competence.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/corpus_churn.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/corpus_size.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/data_residency.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/environment_lifetime.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/existing_cluster.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/existing_iac_tool.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/external_systems.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/hosting.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/human_waiting.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/input_format.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/interpretability_required.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/labelled_count.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/latency_budget_ms.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/licence_posture.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/operates_after_handover.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/output_shape.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/provisioning_api.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/query_pattern.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/recall_span.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/dimensions/sensitivity_present.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/interfaces/Generator.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/interfaces/Guard.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/interfaces/Mapper.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/interfaces/ModelServer.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/interfaces/Parser.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/interfaces/Planner.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/interfaces/Retriever.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/interfaces/Scorer.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/interfaces/Store.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/interfaces/ToolBoundary.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/interfaces/Tracer.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/locales/eu-gdpr.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/locales/in-dpdp.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/ansible-playbook.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/assisted-deterministic.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/audit-only.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/boundary-and-audit.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/cascade-reasoning.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/cascade-representation.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/cascade-retrieval.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/classical-ml-reasoning.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/classical-ml.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/compose.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/decision-log.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/deterministic-masking.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/deterministic.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/direct-call.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/episodic-store.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/explainability-record.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/field-match.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/finetune-representation.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/finetune.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/fixed-sequence.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/gitops.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/governed-tools.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/graph-expanded-retrieval.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/graph-retrieval.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/hybrid-search.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/judged.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/keyword-search.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/kubernetes-manifests.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/labelled-decision.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/labelled-metrics.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/llm-representation.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/llm-scrubbing.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/llm.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/local-embedding.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/managed-api.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/managed-embedding.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/manual-runbook.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/model-planner.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/ocr-pipeline.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/optimisation-reasoning.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/optimisation.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/passthrough.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/reranked-retrieval.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/role-scoped-authority.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/segmentation.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/self-hosted.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/serverless-gpu.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/speech-transcription.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/structured-logs.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/systemd-unit.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/terraform-module.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/text-extraction.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/traced.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/vector-search.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/video-ingestion.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/windowed-ingestion.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/patterns/working-state.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/langgraph.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/llamaindex.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/local-judge.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/mcp.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/ollama.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/openai-judge.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/opentelemetry.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/ortools.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/peft.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/pgvector.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/plain-python.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/qdrant.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/supermemory.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/tesseract.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/vllm.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/whisper.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/stacks/xgboost.md +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/accountability/decision-log.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/accountability/explainability-record.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/deployment/compose.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/deployment/kubernetes-manifests.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/deployment/systemd-unit.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/embedding/local-embedding.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/embedding/managed-embedding.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/evaluation/field-match.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/evaluation/judged.local-judge.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/evaluation/judged.openai-judge.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/evaluation/judged.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/evaluation/labelled-metrics.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/evaluation/labelled-metrics.xgboost.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/governance/audit-only.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/governance/boundary-and-audit.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/governance/role-scoped-authority.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/integration/direct-call.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/integration/governed-tools.mcp.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/integration/governed-tools.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/memory/episodic-store.pgvector.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/memory/episodic-store.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/memory/episodic-store.supermemory.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/memory/working-state.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/observability/structured-logs.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/observability/traced.opentelemetry.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/observability/traced.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/perception/ocr-pipeline.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/perception/ocr-pipeline.tesseract.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/perception/passthrough.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/perception/speech-transcription.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/perception/speech-transcription.whisper.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/perception/text-extraction.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/perception/video-ingestion.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/perception/windowed-ingestion.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/planning/fixed-sequence.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/planning/model-planner.langgraph.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/planning/model-planner.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/planning/optimisation.ortools.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/planning/optimisation.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/provisioning/ansible-playbook.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/provisioning/gitops.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/provisioning/manual-runbook.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/provisioning/terraform-module.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/reasoning/cascade.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/reasoning/classical-ml.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/reasoning/classical-ml.xgboost.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/reasoning/finetune.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/reasoning/labelled-decision.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/reasoning/llm.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/reasoning/optimisation.ortools.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/reasoning/optimisation.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/redaction/deterministic-masking.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/redaction/llm-scrubbing.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/representation/assisted.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/representation/cascade.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/representation/classical-ml.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/representation/classical-ml.xgboost.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/representation/deterministic.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/representation/finetune.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/representation/llm.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/representation/segmentation.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/retrieval/cascade.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/retrieval/graph-expanded-retrieval.pgvector.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/retrieval/graph-expanded-retrieval.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/retrieval/graph-expanded-retrieval.qdrant.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/retrieval/graph-retrieval.pgvector.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/retrieval/graph-retrieval.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/retrieval/graph-retrieval.qdrant.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/retrieval/hybrid-search.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/retrieval/keyword-search.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/retrieval/reranked-retrieval.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/retrieval/vector-search.llamaindex.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/retrieval/vector-search.pgvector.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/retrieval/vector-search.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/retrieval/vector-search.qdrant.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/serving/managed-api.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/serving/self-hosted.ollama.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/serving/self-hosted.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/serving/self-hosted.vllm.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/framework/templates/serving/serverless-gpu.plain.py.j2 +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/__init__.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/architect.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/bench.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/costing.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/debt.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/decide.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/decompose.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/deploy.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/drift.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/evolution.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/experiment.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/forecast.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/gates.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/graph.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/history.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/impact.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/implement.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/importer.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/intake/__init__.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/intake/answers.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/intake/documents.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/intake/interview.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/intake/llm_reader.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/intake/prose.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/intake/samples.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/lifecycle.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/mcp_server.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/models/__init__.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/models/base.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/models/fact.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/models/profile.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/models/respondent.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/models/schema.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/moves.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/ops.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/predicate.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/realization.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/registry.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/sandbox.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/scan.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/scorecard.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/space.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/stakeholders.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/stop.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/training.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/value.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/src/fde/workflow.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/__init__.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/conftest.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/models/__init__.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/models/test_profile.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_acceptance.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_access_and_sensitivity.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_answers.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_audit_fixes.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_bench.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_build_receipt.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_cascade.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_cli_engagement.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_cli_evolution.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_cli_gates.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_cli_intake.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_cli_kb.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_cli_robustness.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_cli_samples.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_costing.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_coverage.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_dead_zones.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_debt.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_decide.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_decompose.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_deploy.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_documents.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_drift.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_embedding.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_emit.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_evolution.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_example_transcript.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_experiment.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_factlog.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_finetune.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_finetune_real.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_forecast.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_gates.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_history.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_impact.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_implement.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_importer.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_interview.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_lifecycle.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_llm_reader.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_locales.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_mcp.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_mcp_stdio.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_memory_retrieval.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_more_templates.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_moves.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_multimodal.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_next.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_ops.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_outcome_contract.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_package.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_prose.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_realization.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_registry.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_release_consistency.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_remaining.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_retrieval_eval.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_reversibility.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_samples.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_sandbox.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_scan.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_schema.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_scorecard.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_serving.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_shipped_registry.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_space.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_stack_swap.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_stakeholders.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_supermemory.py +0 -0
- {fde_framework-0.1.45 → fde_framework-0.1.46}/tests/test_templates.py +0 -0
- {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.
|
|
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,
|
|
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
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
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
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
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
|
|
485
|
-
variable the code reads
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
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
|
|
542
|
-
who put it there
|
|
543
|
-
|
|
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
|
|
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,
|
|
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
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
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
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
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
|
|
441
|
-
variable the code reads
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
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
|
|
498
|
-
who put it there
|
|
499
|
-
|
|
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
|
|
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.
|
|
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
|
|
1898
|
-
build recorded by fde
|
|
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
|
|
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
|
-
|
|
1956
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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)
|