fde-framework 0.1.4__tar.gz → 0.1.6__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.4 → fde_framework-0.1.6}/CHANGELOG.md +59 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/PKG-INFO +18 -16
- {fde_framework-0.1.4 → fde_framework-0.1.6}/README.md +17 -15
- {fde_framework-0.1.4 → fde_framework-0.1.6}/examples/invoice-extraction/README.md +4 -3
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/stacks/ollama.md +6 -0
- fde_framework-0.1.6/framework/stacks/vllm.md +21 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/retrieval/graph-expanded-retrieval.pgvector.py.j2 +6 -1
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/retrieval/graph-expanded-retrieval.plain.py.j2 +5 -2
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/retrieval/graph-expanded-retrieval.qdrant.py.j2 +8 -2
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/retrieval/graph-retrieval.qdrant.py.j2 +2 -2
- {fde_framework-0.1.4 → fde_framework-0.1.6}/pyproject.toml +1 -1
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/architect.py +10 -1
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/cli.py +39 -3
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/decide.py +16 -3
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/emit.py +92 -27
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/gates.py +4 -1
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/ops.py +72 -20
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/scan.py +23 -1
- fde_framework-0.1.6/tests/test_audit_fixes.py +237 -0
- fde_framework-0.1.6/tests/test_build_receipt.py +101 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_retrieval_eval.py +103 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_scan.py +37 -0
- fde_framework-0.1.4/framework/stacks/vllm.md +0 -9
- {fde_framework-0.1.4 → fde_framework-0.1.6}/.gitignore +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/LICENSE +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/ansible-playbook.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/assisted-deterministic.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/audit-only.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/boundary-and-audit.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/cascade.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/classical-ml.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/compose.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/decision-log.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/deterministic-masking.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/deterministic.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/direct-call.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/episodic-store.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/explainability-record.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/field-match.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/finetune.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/fixed-sequence.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/gitops.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/governed-tools.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/graph-expanded-retrieval.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/graph-retrieval.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/hybrid-search.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/judged.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/keyword-search.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/kubernetes-manifests.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/labelled-metrics.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/llm-extraction.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/llm-scrubbing.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/llm.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/local-embedding.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/managed-api.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/managed-embedding.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/manual-runbook.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/model-planner.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/ocr-pipeline.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/optimisation-reasoning.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/optimisation.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/passthrough.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/reranked-retrieval.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/role-scoped-authority.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/segmentation.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/self-hosted.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/serverless-gpu.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/speech-transcription.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/structured-logs.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/systemd-unit.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/terraform-module.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/text-extraction.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/traced.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/vector-search.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/video-ingestion.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/windowed-ingestion.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/approaches/working-state.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/cases/churn-scoring.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/cases/route-planning.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/cases/structured-extraction.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/cases/studio-style.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/components/accountability.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/components/deployment.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/components/embedding.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/components/evaluation.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/components/governance.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/components/integration.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/components/memory.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/components/observability.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/components/perception.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/components/planning.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/components/provisioning.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/components/reasoning.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/components/redaction.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/components/representation.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/components/retrieval.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/components/serving.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/dimensions/accelerator.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/dimensions/access_model.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/dimensions/arrival_rate.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/dimensions/availability_target.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/dimensions/cheap_path_coverage.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/dimensions/confidence_calibrated.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/dimensions/container_competence.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/dimensions/corpus_churn.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/dimensions/corpus_size.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/dimensions/data_residency.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/dimensions/environment_lifetime.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/dimensions/existing_cluster.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/dimensions/existing_iac_tool.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/dimensions/external_systems.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/dimensions/hosting.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/dimensions/human_waiting.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/dimensions/input_format.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/dimensions/interpretability_required.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/dimensions/labelled_count.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/dimensions/latency_budget_ms.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/dimensions/licence_posture.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/dimensions/operates_after_handover.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/dimensions/output_shape.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/dimensions/provisioning_api.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/dimensions/query_pattern.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/dimensions/recall_span.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/dimensions/sensitivity_present.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/interfaces/Generator.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/interfaces/Guard.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/interfaces/Mapper.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/interfaces/ModelServer.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/interfaces/Parser.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/interfaces/Planner.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/interfaces/Retriever.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/interfaces/Scorer.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/interfaces/Store.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/interfaces/ToolBoundary.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/interfaces/Tracer.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/locales/eu-gdpr.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/locales/in-dpdp.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/ansible-playbook.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/assisted-deterministic.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/audit-only.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/boundary-and-audit.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/cascade-reasoning.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/cascade-representation.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/cascade-retrieval.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/classical-ml-reasoning.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/classical-ml.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/compose.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/decision-log.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/deterministic-masking.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/deterministic.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/direct-call.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/episodic-store.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/explainability-record.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/field-match.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/finetune-representation.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/finetune.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/fixed-sequence.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/gitops.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/governed-tools.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/graph-expanded-retrieval.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/graph-retrieval.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/hybrid-search.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/judged.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/keyword-search.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/kubernetes-manifests.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/labelled-metrics.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/llm-representation.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/llm-scrubbing.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/llm.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/local-embedding.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/managed-api.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/managed-embedding.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/manual-runbook.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/model-planner.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/ocr-pipeline.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/optimisation-reasoning.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/optimisation.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/passthrough.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/reranked-retrieval.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/role-scoped-authority.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/segmentation.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/self-hosted.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/serverless-gpu.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/speech-transcription.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/structured-logs.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/systemd-unit.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/terraform-module.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/text-extraction.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/traced.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/vector-search.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/video-ingestion.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/windowed-ingestion.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/patterns/working-state.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/stacks/langgraph.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/stacks/llamaindex.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/stacks/local-judge.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/stacks/mcp.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/stacks/openai-judge.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/stacks/opentelemetry.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/stacks/ortools.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/stacks/pgvector.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/stacks/plain-python.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/stacks/qdrant.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/stacks/tesseract.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/stacks/whisper.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/stacks/xgboost.md +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/accountability/decision-log.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/accountability/explainability-record.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/deployment/compose.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/deployment/kubernetes-manifests.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/deployment/systemd-unit.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/embedding/local-embedding.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/embedding/managed-embedding.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/evaluation/field-match.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/evaluation/judged.local-judge.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/evaluation/judged.openai-judge.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/evaluation/judged.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/evaluation/labelled-metrics.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/evaluation/labelled-metrics.xgboost.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/governance/audit-only.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/governance/boundary-and-audit.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/governance/role-scoped-authority.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/integration/direct-call.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/integration/governed-tools.mcp.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/integration/governed-tools.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/memory/episodic-store.pgvector.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/memory/episodic-store.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/memory/working-state.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/observability/structured-logs.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/observability/traced.opentelemetry.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/observability/traced.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/perception/ocr-pipeline.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/perception/ocr-pipeline.tesseract.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/perception/passthrough.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/perception/speech-transcription.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/perception/speech-transcription.whisper.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/perception/text-extraction.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/perception/video-ingestion.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/perception/windowed-ingestion.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/planning/fixed-sequence.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/planning/model-planner.langgraph.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/planning/model-planner.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/planning/optimisation.ortools.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/planning/optimisation.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/provisioning/ansible-playbook.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/provisioning/gitops.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/provisioning/manual-runbook.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/provisioning/terraform-module.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/reasoning/cascade.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/reasoning/classical-ml.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/reasoning/classical-ml.xgboost.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/reasoning/finetune.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/reasoning/llm.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/reasoning/optimisation.ortools.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/reasoning/optimisation.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/redaction/deterministic-masking.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/redaction/llm-scrubbing.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/representation/assisted.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/representation/cascade.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/representation/classical-ml.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/representation/classical-ml.xgboost.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/representation/deterministic.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/representation/finetune.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/representation/llm.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/representation/segmentation.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/retrieval/cascade.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/retrieval/graph-retrieval.pgvector.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/retrieval/graph-retrieval.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/retrieval/hybrid-search.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/retrieval/keyword-search.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/retrieval/reranked-retrieval.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/retrieval/vector-search.llamaindex.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/retrieval/vector-search.pgvector.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/retrieval/vector-search.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/retrieval/vector-search.qdrant.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/serving/managed-api.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/serving/self-hosted.ollama.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/serving/self-hosted.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/serving/self-hosted.vllm.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/framework/templates/serving/serverless-gpu.plain.py.j2 +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/__init__.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/costing.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/decompose.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/deploy.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/evolution.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/factlog.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/graph.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/implement.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/intake/__init__.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/intake/answers.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/intake/documents.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/intake/interview.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/intake/llm_reader.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/intake/prose.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/intake/samples.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/models/__init__.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/models/base.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/models/fact.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/models/profile.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/models/respondent.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/models/schema.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/moves.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/predicate.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/realization.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/registry.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/space.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/src/fde/workflow.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/__init__.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/conftest.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/models/__init__.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/models/test_profile.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_access_and_sensitivity.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_answers.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_cascade.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_cli_engagement.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_cli_evolution.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_cli_gates.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_cli_intake.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_cli_kb.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_cli_robustness.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_cli_samples.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_costing.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_coverage.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_dead_zones.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_decide.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_decompose.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_deploy.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_documents.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_embedding.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_emit.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_evolution.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_example_transcript.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_factlog.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_gates.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_implement.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_interview.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_llm_reader.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_locales.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_memory_retrieval.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_more_templates.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_moves.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_multimodal.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_ops.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_package.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_prose.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_realization.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_registry.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_remaining.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_reversibility.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_samples.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_sanitisation.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_schema.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_serving.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_shipped_registry.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_space.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_stack_swap.py +0 -0
- {fde_framework-0.1.4 → fde_framework-0.1.6}/tests/test_templates.py +0 -0
|
@@ -5,6 +5,65 @@ 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.6] — 2026-09-10
|
|
9
|
+
|
|
10
|
+
Found by the first full demonstration engagement — 626 real scanned
|
|
11
|
+
receipts (SROIE) run through the complete lifecycle on the published
|
|
12
|
+
wheel:
|
|
13
|
+
|
|
14
|
+
- `fde build <bare-name>` resolved the engagement but read the sample
|
|
15
|
+
pairs from the raw argument's path, silently emitting a project with an
|
|
16
|
+
empty golden set while sixty verified pairs sat on the engagement. The
|
|
17
|
+
harness's empty-exam refusal caught it at runtime; now the path is
|
|
18
|
+
resolved once, and the build receipt prints its own exam counts
|
|
19
|
+
("evals: 42 golden, …") with a pointed warning when pairs exist but
|
|
20
|
+
none reached the golden set.
|
|
21
|
+
- The local-engine choice is a concurrency decision, not only a hardware
|
|
22
|
+
one: `fde scan <engagement>` now reads the recorded arrival rate, and
|
|
23
|
+
past ~1000 requests/day (where the gap between requests drops under a
|
|
24
|
+
generation's length) it names the sequential-queue ceiling and the
|
|
25
|
+
continuous-batching answer. The vllm and ollama stack entries carry the
|
|
26
|
+
doctrine: paged KV admits more concurrent sequences, the scheduler
|
|
27
|
+
retires requests mid-batch, and the crossover is measured, never guessed.
|
|
28
|
+
|
|
29
|
+
## [0.1.5] — 2026-09-10
|
|
30
|
+
|
|
31
|
+
Three independent fresh-eyes auditors ran against 0.1.4 the day it shipped
|
|
32
|
+
— an adversarial code review, a stranger following only the public docs,
|
|
33
|
+
and a claims audit. Everything they caught, in one release:
|
|
34
|
+
|
|
35
|
+
- The retrieval eval now grades every realization shape the registry can
|
|
36
|
+
emit: a wired module-level instance wins over a fresh construction (a
|
|
37
|
+
working deployment no longer scores 0% with the index blamed), class
|
|
38
|
+
`run(query, top_k=…)` shapes are called correctly, and path-contract
|
|
39
|
+
graph-retrieval is excluded from the recall gate it could never pass.
|
|
40
|
+
Recall math hardened: duplicate relevant ids no longer inflate, wrong-
|
|
41
|
+
shaped results are errors rather than silent zeros diluting a green CI.
|
|
42
|
+
- `graph-retrieval.qdrant`'s expansion loop yielded the wrong variable
|
|
43
|
+
since v0.1.3 — the graph walk was dead code and the approach silently
|
|
44
|
+
degraded to vector search. Fixed and pinned by executing the template.
|
|
45
|
+
The graph-expanded variant survives adjacency entries for deleted
|
|
46
|
+
documents (the continuous-churn case it exists for) and all three
|
|
47
|
+
variants cap expansion breadth, not just depth.
|
|
48
|
+
- The emitted `ops/slo.md` now shows the captured baseline as the numbers
|
|
49
|
+
to beat — it said "Not captured" over a recorded baseline, contradicting
|
|
50
|
+
its own acceptance protocol. `evals/acceptance.md` stops citing a named
|
|
51
|
+
eval owner when the client_readiness gate was waived, and stops citing
|
|
52
|
+
"those 0" cases over an empty golden set.
|
|
53
|
+
- The architecture fingerprint now includes the topology: two engagements
|
|
54
|
+
building byte-different projects (different boundaries) no longer share
|
|
55
|
+
a fingerprint.
|
|
56
|
+
- The interview no longer re-asks a multi-valued question it just
|
|
57
|
+
accepted; the offline_evaluability remedy names its clearing command;
|
|
58
|
+
a rejection whose applies-condition references an unanswered dimension
|
|
59
|
+
now names the question that could reverse it.
|
|
60
|
+
- Docs truth pass: the quickstart names all three gate steps before the
|
|
61
|
+
passing build; the emitted-project tree shows `ops/diagnosis.md` and
|
|
62
|
+
`evals/retrieval.py`; kb commands documented registry-free as they ship;
|
|
63
|
+
README nav links absolute so they resolve on PyPI; ARCHITECTURE.md
|
|
64
|
+
diagram says seven gates; CITATION.cff current; CI checks out full
|
|
65
|
+
history so the sanitisation scan covers what the README says it covers.
|
|
66
|
+
|
|
8
67
|
## [0.1.4] — 2026-09-09
|
|
9
68
|
|
|
10
69
|
The measurement release: claims the framework already made, turned into
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: fde-framework
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.6
|
|
4
4
|
Summary: A framework for Forward Deployed Engineers: from problem statement to a deployable AI project, every decision traced to a fact.
|
|
5
5
|
Project-URL: Homepage, https://github.com/atulkapoor/fde-framework
|
|
6
6
|
Project-URL: Repository, https://github.com/atulkapoor/fde-framework
|
|
@@ -53,9 +53,9 @@ Description-Content-Type: text/markdown
|
|
|
53
53
|
<p>
|
|
54
54
|
<a href="#install">Install</a> ·
|
|
55
55
|
<a href="#try-it">Quickstart</a> ·
|
|
56
|
-
<a href="ARCHITECTURE.md">Architecture</a> ·
|
|
57
|
-
<a href="examples/invoice-extraction
|
|
58
|
-
<a href="CONTRIBUTING.md">Contributing</a> ·
|
|
56
|
+
<a href="https://github.com/atulkapoor/fde-framework/blob/main/ARCHITECTURE.md">Architecture</a> ·
|
|
57
|
+
<a href="https://github.com/atulkapoor/fde-framework/tree/main/examples/invoice-extraction">Worked example</a> ·
|
|
58
|
+
<a href="https://github.com/atulkapoor/fde-framework/blob/main/CONTRIBUTING.md">Contributing</a> ·
|
|
59
59
|
<a href="https://pypi.org/project/fde-framework/">PyPI</a> ·
|
|
60
60
|
<a href="https://atulkapoor.github.io/fde-framework/">Website</a>
|
|
61
61
|
</p>
|
|
@@ -75,9 +75,9 @@ including on-premise, inside a customer VPC, or fully air-gapped.
|
|
|
75
75
|
pip install fde-framework
|
|
76
76
|
fde start acme --statement "Extract fields from supplier invoices."
|
|
77
77
|
fde ask acme --role admin # role-scoped discovery interview
|
|
78
|
-
fde architect acme #
|
|
78
|
+
fde architect acme # topology + chosen approaches (rationale lands in ARCHITECTURE.md)
|
|
79
79
|
fde build acme --out project # refuses: seven gates guard the build
|
|
80
|
-
# ...verify data access, capture the baseline (each gate prints its remedy), then:
|
|
80
|
+
# ...verify data access, capture the baseline, name the eval owner (each gate prints its remedy), then:
|
|
81
81
|
fde build acme --out project # code + evals + deploy assets + runbook
|
|
82
82
|
```
|
|
83
83
|
|
|
@@ -131,9 +131,9 @@ pairs, role-scoped interview, hardware scan) → fact log with provenance →
|
|
|
131
131
|
permutation space → seven gates → decide → architect → build (code, evals,
|
|
132
132
|
deploy and ops assets, `RISKS.md`, `COMPLIANCE.md`) → retro and case
|
|
133
133
|
capture. Overrides are honoured on the next run, trigger observations feed
|
|
134
|
-
calibration, and a reviewed case can enter the corpus. over
|
|
135
|
-
|
|
136
|
-
regression
|
|
134
|
+
calibration, and a reviewed case can enter the corpus. over 870 tests; four
|
|
135
|
+
fresh-eyes review rounds (142 findings, each resolved and the fixes pinned
|
|
136
|
+
as regression tests); CI gates on the suite, lint, and a sanitisation scan of
|
|
137
137
|
the tree *and its history*; the evidence corpus is anchored to publicly
|
|
138
138
|
documented production deployments; every decision is reproducible from its
|
|
139
139
|
inputs.
|
|
@@ -265,8 +265,8 @@ fde scan engagements/acme # what this hardware runs
|
|
|
265
265
|
fde cost --requests-per-day 500000 --model-b 70 # dated fleet sizing
|
|
266
266
|
|
|
267
267
|
fde kb validate # parse and cross-link the registry
|
|
268
|
-
fde kb gaps
|
|
269
|
-
fde kb sweep
|
|
268
|
+
fde kb gaps # what the corpus is missing
|
|
269
|
+
fde kb sweep # profiles no approach can serve
|
|
270
270
|
.venv/bin/pytest -q
|
|
271
271
|
```
|
|
272
272
|
|
|
@@ -290,10 +290,11 @@ project/
|
|
|
290
290
|
│ └── llm.py # the one model touchpoint — when a decision needs a model (boundary-gated)
|
|
291
291
|
├── evals/ # golden / edge / adversarial sets from the client's own pairs
|
|
292
292
|
│ ├── harness.py # fails CI until implemented; judge-based when the evaluation decided judged
|
|
293
|
+
│ ├── retrieval.py # recall@10/50 of the retrieval layer alone — when retrieval answers ranked queries
|
|
293
294
|
│ ├── acceptance.md # blind UAT protocol for the client's own judges
|
|
294
295
|
│ └── load.py # p95 against the stated budget (when one was stated)
|
|
295
296
|
├── deploy/ # the substrate that was earned + TEARDOWN.md for all of it
|
|
296
|
-
├── ops/ # runbook keyed to the failure taxonomy, SLOs, rollback
|
|
297
|
+
├── ops/ # runbook keyed to the failure taxonomy, diagnosis walk, SLOs, rollback
|
|
297
298
|
├── ARCHITECTURE.md # scope read-out, decisions, tools & alternatives, agent posture
|
|
298
299
|
├── RISKS.md # every waived gate and overridden recommendation
|
|
299
300
|
└── COMPLIANCE.md # jurisdiction obligations, when a locale pack was applied
|
|
@@ -327,7 +328,7 @@ fde security-review acme --note "client infosec walked the data paths"
|
|
|
327
328
|
fde ask acme --role eval_owner # or: fde waive acme client_readiness --reason "..."
|
|
328
329
|
|
|
329
330
|
fde build acme --out project # refuses until the gates truly pass
|
|
330
|
-
python project/evals/harness.py # red until implemented -- that's the exam
|
|
331
|
+
python project/evals/harness.py # red: empty until pairs are seeded, then red until implemented -- that's the exam
|
|
331
332
|
fde implement project # drive a coding agent until it's green
|
|
332
333
|
```
|
|
333
334
|
|
|
@@ -389,8 +390,9 @@ the same receipts the emitted `ARCHITECTURE.md` prints.
|
|
|
389
390
|
|
|
390
391
|
## Troubleshooting
|
|
391
392
|
|
|
392
|
-
**`no registry here`** —
|
|
393
|
-
|
|
393
|
+
**`no registry here`** — you passed `--registry`/`--root` at a directory that
|
|
394
|
+
holds no registry. Drop the flag (the corpus ships inside the package) or
|
|
395
|
+
point it at the `framework/` of a source checkout.
|
|
394
396
|
|
|
395
397
|
**`build` refuses with gates listed** — that is the point. `fde status`
|
|
396
398
|
names each gate and its remedy; soft gates take `fde waive <gate> --reason`,
|
|
@@ -546,7 +548,7 @@ The registry is the shared asset; engagements are private working state.
|
|
|
546
548
|
```bash
|
|
547
549
|
git clone https://github.com/atulkapoor/fde-framework.git && cd fde-framework
|
|
548
550
|
python3 -m venv .venv && .venv/bin/pip install -e ".[dev,documents]"
|
|
549
|
-
.venv/bin/pytest -q # ~
|
|
551
|
+
.venv/bin/pytest -q # ~880 tests, < 60s
|
|
550
552
|
.venv/bin/ruff check src tests
|
|
551
553
|
```
|
|
552
554
|
|
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
<p>
|
|
16
16
|
<a href="#install">Install</a> ·
|
|
17
17
|
<a href="#try-it">Quickstart</a> ·
|
|
18
|
-
<a href="ARCHITECTURE.md">Architecture</a> ·
|
|
19
|
-
<a href="examples/invoice-extraction
|
|
20
|
-
<a href="CONTRIBUTING.md">Contributing</a> ·
|
|
18
|
+
<a href="https://github.com/atulkapoor/fde-framework/blob/main/ARCHITECTURE.md">Architecture</a> ·
|
|
19
|
+
<a href="https://github.com/atulkapoor/fde-framework/tree/main/examples/invoice-extraction">Worked example</a> ·
|
|
20
|
+
<a href="https://github.com/atulkapoor/fde-framework/blob/main/CONTRIBUTING.md">Contributing</a> ·
|
|
21
21
|
<a href="https://pypi.org/project/fde-framework/">PyPI</a> ·
|
|
22
22
|
<a href="https://atulkapoor.github.io/fde-framework/">Website</a>
|
|
23
23
|
</p>
|
|
@@ -37,9 +37,9 @@ including on-premise, inside a customer VPC, or fully air-gapped.
|
|
|
37
37
|
pip install fde-framework
|
|
38
38
|
fde start acme --statement "Extract fields from supplier invoices."
|
|
39
39
|
fde ask acme --role admin # role-scoped discovery interview
|
|
40
|
-
fde architect acme #
|
|
40
|
+
fde architect acme # topology + chosen approaches (rationale lands in ARCHITECTURE.md)
|
|
41
41
|
fde build acme --out project # refuses: seven gates guard the build
|
|
42
|
-
# ...verify data access, capture the baseline (each gate prints its remedy), then:
|
|
42
|
+
# ...verify data access, capture the baseline, name the eval owner (each gate prints its remedy), then:
|
|
43
43
|
fde build acme --out project # code + evals + deploy assets + runbook
|
|
44
44
|
```
|
|
45
45
|
|
|
@@ -93,9 +93,9 @@ pairs, role-scoped interview, hardware scan) → fact log with provenance →
|
|
|
93
93
|
permutation space → seven gates → decide → architect → build (code, evals,
|
|
94
94
|
deploy and ops assets, `RISKS.md`, `COMPLIANCE.md`) → retro and case
|
|
95
95
|
capture. Overrides are honoured on the next run, trigger observations feed
|
|
96
|
-
calibration, and a reviewed case can enter the corpus. over
|
|
97
|
-
|
|
98
|
-
regression
|
|
96
|
+
calibration, and a reviewed case can enter the corpus. over 870 tests; four
|
|
97
|
+
fresh-eyes review rounds (142 findings, each resolved and the fixes pinned
|
|
98
|
+
as regression tests); CI gates on the suite, lint, and a sanitisation scan of
|
|
99
99
|
the tree *and its history*; the evidence corpus is anchored to publicly
|
|
100
100
|
documented production deployments; every decision is reproducible from its
|
|
101
101
|
inputs.
|
|
@@ -227,8 +227,8 @@ fde scan engagements/acme # what this hardware runs
|
|
|
227
227
|
fde cost --requests-per-day 500000 --model-b 70 # dated fleet sizing
|
|
228
228
|
|
|
229
229
|
fde kb validate # parse and cross-link the registry
|
|
230
|
-
fde kb gaps
|
|
231
|
-
fde kb sweep
|
|
230
|
+
fde kb gaps # what the corpus is missing
|
|
231
|
+
fde kb sweep # profiles no approach can serve
|
|
232
232
|
.venv/bin/pytest -q
|
|
233
233
|
```
|
|
234
234
|
|
|
@@ -252,10 +252,11 @@ project/
|
|
|
252
252
|
│ └── llm.py # the one model touchpoint — when a decision needs a model (boundary-gated)
|
|
253
253
|
├── evals/ # golden / edge / adversarial sets from the client's own pairs
|
|
254
254
|
│ ├── harness.py # fails CI until implemented; judge-based when the evaluation decided judged
|
|
255
|
+
│ ├── retrieval.py # recall@10/50 of the retrieval layer alone — when retrieval answers ranked queries
|
|
255
256
|
│ ├── acceptance.md # blind UAT protocol for the client's own judges
|
|
256
257
|
│ └── load.py # p95 against the stated budget (when one was stated)
|
|
257
258
|
├── deploy/ # the substrate that was earned + TEARDOWN.md for all of it
|
|
258
|
-
├── ops/ # runbook keyed to the failure taxonomy, SLOs, rollback
|
|
259
|
+
├── ops/ # runbook keyed to the failure taxonomy, diagnosis walk, SLOs, rollback
|
|
259
260
|
├── ARCHITECTURE.md # scope read-out, decisions, tools & alternatives, agent posture
|
|
260
261
|
├── RISKS.md # every waived gate and overridden recommendation
|
|
261
262
|
└── COMPLIANCE.md # jurisdiction obligations, when a locale pack was applied
|
|
@@ -289,7 +290,7 @@ fde security-review acme --note "client infosec walked the data paths"
|
|
|
289
290
|
fde ask acme --role eval_owner # or: fde waive acme client_readiness --reason "..."
|
|
290
291
|
|
|
291
292
|
fde build acme --out project # refuses until the gates truly pass
|
|
292
|
-
python project/evals/harness.py # red until implemented -- that's the exam
|
|
293
|
+
python project/evals/harness.py # red: empty until pairs are seeded, then red until implemented -- that's the exam
|
|
293
294
|
fde implement project # drive a coding agent until it's green
|
|
294
295
|
```
|
|
295
296
|
|
|
@@ -351,8 +352,9 @@ the same receipts the emitted `ARCHITECTURE.md` prints.
|
|
|
351
352
|
|
|
352
353
|
## Troubleshooting
|
|
353
354
|
|
|
354
|
-
**`no registry here`** —
|
|
355
|
-
|
|
355
|
+
**`no registry here`** — you passed `--registry`/`--root` at a directory that
|
|
356
|
+
holds no registry. Drop the flag (the corpus ships inside the package) or
|
|
357
|
+
point it at the `framework/` of a source checkout.
|
|
356
358
|
|
|
357
359
|
**`build` refuses with gates listed** — that is the point. `fde status`
|
|
358
360
|
names each gate and its remedy; soft gates take `fde waive <gate> --reason`,
|
|
@@ -508,7 +510,7 @@ The registry is the shared asset; engagements are private working state.
|
|
|
508
510
|
```bash
|
|
509
511
|
git clone https://github.com/atulkapoor/fde-framework.git && cd fde-framework
|
|
510
512
|
python3 -m venv .venv && .venv/bin/pip install -e ".[dev,documents]"
|
|
511
|
-
.venv/bin/pytest -q # ~
|
|
513
|
+
.venv/bin/pytest -q # ~880 tests, < 60s
|
|
512
514
|
.venv/bin/ruff check src tests
|
|
513
515
|
```
|
|
514
516
|
|
|
@@ -45,7 +45,7 @@ fde security-review engagements/acme --note "client infosec reviewed data paths
|
|
|
45
45
|
fde waive engagements/acme client_readiness --reason "eval owner named, starts Monday"
|
|
46
46
|
|
|
47
47
|
fde architect engagements/acme
|
|
48
|
-
# topology on-prem [
|
|
48
|
+
# topology on-prem [de84a4cea7cc42b9]
|
|
49
49
|
# deployment systemd-unit via plain-python
|
|
50
50
|
# evaluation field-match via plain-python
|
|
51
51
|
# governance boundary-and-audit via plain-python
|
|
@@ -57,6 +57,7 @@ fde architect engagements/acme
|
|
|
57
57
|
|
|
58
58
|
fde build engagements/acme --out project
|
|
59
59
|
# wrote project
|
|
60
|
+
# next: fde implement project --holdout engagements/acme/artifacts/holdout.jsonl
|
|
60
61
|
```
|
|
61
62
|
|
|
62
63
|
The emitted `project/` holds `app/` (pipeline in topological order, boundary
|
|
@@ -64,7 +65,7 @@ check imported at startup because data cannot leave), `evals/` (golden set
|
|
|
64
65
|
from the three pairs, a harness that fails CI until the pipeline is
|
|
65
66
|
implemented, and `acceptance.md` — a blind-judging protocol for the client's
|
|
66
67
|
own people), `deploy/` (a systemd unit — rung zero, because nothing in the
|
|
67
|
-
profile earned a container), `ops/` (runbook, SLOs, rollback),
|
|
68
|
+
profile earned a container), `ops/` (runbook, diagnosis walk, SLOs, rollback),
|
|
68
69
|
`ARCHITECTURE.md` with the scope read-out, the tools table with
|
|
69
70
|
in-topology alternatives, the agent posture, and every rejected
|
|
70
71
|
alternative, and `RISKS.md` recording the one waived gate and its reason.
|
|
@@ -82,7 +83,7 @@ fde retro engagements/acme --outcome "delivered" --days 18
|
|
|
82
83
|
Notice what the decisions did *not* do: no vector database for a lookup
|
|
83
84
|
workload, no Kubernetes for a single service, no LLM in the extraction path
|
|
84
85
|
while the deterministic mapper's coverage is unmeasured. The fingerprint
|
|
85
|
-
`
|
|
86
|
+
`de84a4cea7cc42b9` is stable — rebuild from the same facts and the diff is
|
|
86
87
|
empty. (The corpus evolves, and a corpus change that moves a decision moves
|
|
87
88
|
this fingerprint with it; the transcript above is re-run against the corpus
|
|
88
89
|
it ships with.)
|
|
@@ -17,3 +17,9 @@ Not a fleet server: no continuous batching, no paged attention. The moment
|
|
|
17
17
|
there are ten concurrent users, this is the wrong stack and vLLM (or SGLang,
|
|
18
18
|
where requests share long prefixes) is the right one -- which is a swap of
|
|
19
19
|
realization, not of architecture.
|
|
20
|
+
|
|
21
|
+
The ceiling is concurrency: generations serve from a sequential queue, so
|
|
22
|
+
overlapping requests stack their latencies. Right for a seat or a team;
|
|
23
|
+
past roughly a thousand requests a day the queue is the system -- move to
|
|
24
|
+
an engine with continuous batching before promising that rate, and
|
|
25
|
+
`fde scan <engagement>` says so from the recorded arrival rate.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: vllm
|
|
3
|
+
name: vLLM
|
|
4
|
+
licence: Apache-2.0
|
|
5
|
+
topologies: [customer-vpc, on-prem, air-gapped, hybrid]
|
|
6
|
+
last_verified: 2026-09-10
|
|
7
|
+
reversibility: moderate
|
|
8
|
+
---
|
|
9
|
+
Serving open weights. Continuous batching and prefix caching by default.
|
|
10
|
+
|
|
11
|
+
What the defaults buy: the KV cache is paged rather than allocated as one
|
|
12
|
+
contiguous block per request, so memory fragments less and admits more
|
|
13
|
+
concurrent sequences; and the scheduler adds and retires requests mid-batch
|
|
14
|
+
instead of waiting for a batch to drain. Together they are why this engine
|
|
15
|
+
holds throughput when requests overlap -- and why a sequential single-box
|
|
16
|
+
runtime that benchmarked fine at one user falls over at twenty.
|
|
17
|
+
|
|
18
|
+
The flip side is operational: vLLM is a service somebody runs (CUDA stack,
|
|
19
|
+
versioned kernels), where the single-box path is one binary. The crossover
|
|
20
|
+
is measured, not guessed: the arrival rate the engagement recorded says
|
|
21
|
+
whether requests overlap, and `fde scan <engagement>` reads it.
|
|
@@ -45,7 +45,9 @@ LIMIT %(k)s;
|
|
|
45
45
|
"""
|
|
46
46
|
|
|
47
47
|
# One hop per query, looped in the application: co-mentioned chunks of the
|
|
48
|
-
# frontier, minus everything already found.
|
|
48
|
+
# frontier, minus everything already found. Depth is bounded by the loop and
|
|
49
|
+
# breadth by the pool cap -- depth alone is not a bound, because one hub
|
|
50
|
+
# entity can pull the whole corpus in on a single hop.
|
|
49
51
|
EXPAND_SQL = """
|
|
50
52
|
SELECT DISTINCT m2.chunk_id, c.body
|
|
51
53
|
FROM {table}_mentions m1
|
|
@@ -72,6 +74,7 @@ class {{ class_name }}:
|
|
|
72
74
|
dimensions: int = 768,
|
|
73
75
|
max_hops: int = 2,
|
|
74
76
|
seeds: int = 20,
|
|
77
|
+
max_pool: int = 200,
|
|
75
78
|
) -> None:
|
|
76
79
|
self.connection = connection
|
|
77
80
|
self.embed = embed
|
|
@@ -80,6 +83,7 @@ class {{ class_name }}:
|
|
|
80
83
|
self.dimensions = dimensions
|
|
81
84
|
self.max_hops = max_hops
|
|
82
85
|
self.seeds = seeds
|
|
86
|
+
self.max_pool = max_pool
|
|
83
87
|
|
|
84
88
|
def schema(self) -> str:
|
|
85
89
|
return SCHEMA_SQL.format(table=self.table, dimensions=self.dimensions)
|
|
@@ -102,6 +106,7 @@ class {{ class_name }}:
|
|
|
102
106
|
{"frontier": frontier, "found": list(found)},
|
|
103
107
|
)
|
|
104
108
|
fresh = cursor.fetchall()
|
|
109
|
+
fresh = fresh[: max(0, self.max_pool - len(found))]
|
|
105
110
|
if not fresh:
|
|
106
111
|
break
|
|
107
112
|
for row in fresh:
|
|
@@ -20,8 +20,9 @@ approach = "{{ approach }}"
|
|
|
20
20
|
stack = "{{ stack }}"
|
|
21
21
|
|
|
22
22
|
TOP_K = 8
|
|
23
|
-
SEEDS = 20
|
|
24
|
-
MAX_HOPS = 2
|
|
23
|
+
SEEDS = 20 # vector recall opens the graph; it does not need to finish the job
|
|
24
|
+
MAX_HOPS = 2 # each hop multiplies the pool, and two answers most questions
|
|
25
|
+
MAX_POOL = 200 # depth alone is not a bound: one hub entity can pull the corpus in
|
|
25
26
|
|
|
26
27
|
# Injected at wiring time: retrieve(query, k) -> seed chunks (each a dict with
|
|
27
28
|
# at least id, text, entities); rerank(query, text) -> relevance, higher is
|
|
@@ -54,6 +55,8 @@ class {{ class_name }}:
|
|
|
54
55
|
]
|
|
55
56
|
fresh = {c["id"]: {**c, "hop": hop}
|
|
56
57
|
for c in connected if c["id"] not in pool}
|
|
58
|
+
room = max(0, MAX_POOL - len(pool))
|
|
59
|
+
fresh = dict(list(fresh.items())[:room])
|
|
57
60
|
if not fresh:
|
|
58
61
|
break
|
|
59
62
|
pool.update(fresh)
|
|
@@ -24,7 +24,8 @@ stack = "{{ stack }}"
|
|
|
24
24
|
COLLECTION = "{{ component }}_chunks"
|
|
25
25
|
TOP_K = 8
|
|
26
26
|
SEEDS = 20
|
|
27
|
-
MAX_HOPS = 2
|
|
27
|
+
MAX_HOPS = 2 # bounded: each hop multiplies latency, and two answers most questions
|
|
28
|
+
MAX_POOL = 200 # depth alone is not a bound: one hub entity can pull the corpus in
|
|
28
29
|
|
|
29
30
|
|
|
30
31
|
class QdrantUnwired(RuntimeError):
|
|
@@ -62,6 +63,7 @@ def run(query: str, top_k: int = TOP_K) -> list[dict]:
|
|
|
62
63
|
for chunk_id in adjacency.get(entity, [])
|
|
63
64
|
]
|
|
64
65
|
fresh = [c for c in dict.fromkeys(connected) if c not in found]
|
|
66
|
+
fresh = fresh[: max(0, MAX_POOL - len(found))]
|
|
65
67
|
if not fresh:
|
|
66
68
|
break
|
|
67
69
|
records = client.retrieve(collection_name=COLLECTION, ids=fresh,
|
|
@@ -69,7 +71,11 @@ def run(query: str, top_k: int = TOP_K) -> list[dict]:
|
|
|
69
71
|
for record in records:
|
|
70
72
|
found[str(record.id)] = {"id": str(record.id), "hop": hop,
|
|
71
73
|
**(record.payload or {})}
|
|
72
|
-
|
|
74
|
+
# Only ids the store actually returned: on a corpus that keeps
|
|
75
|
+
# changing, the adjacency map can name a chunk deleted since the
|
|
76
|
+
# last rebuild, and walking from a ghost is a KeyError in the exact
|
|
77
|
+
# scenario this variant exists for.
|
|
78
|
+
frontier = [str(record.id) for record in records]
|
|
73
79
|
scored = [
|
|
74
80
|
{**c, "rerank_score": rerank(query, c.get("text", ""))}
|
|
75
81
|
for c in found.values()
|
|
@@ -54,10 +54,10 @@ def run(query: str, top_k: int = TOP_K) -> list[dict]:
|
|
|
54
54
|
frontier = list(found)
|
|
55
55
|
for hop in range(1, MAX_HOPS + 1):
|
|
56
56
|
connected = [
|
|
57
|
-
|
|
57
|
+
neighbour
|
|
58
58
|
for chunk_id in frontier
|
|
59
59
|
for entity in found[chunk_id].get("entities", [])
|
|
60
|
-
for
|
|
60
|
+
for neighbour in adjacency.get(entity, [])
|
|
61
61
|
]
|
|
62
62
|
fresh = [c for c in dict.fromkeys(connected) if c not in found]
|
|
63
63
|
if not fresh:
|
|
@@ -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.6"
|
|
6
6
|
description = "A framework for Forward Deployed Engineers: from problem statement to a deployable AI project, every decision traced to a fact."
|
|
7
7
|
readme = "README.md"
|
|
8
8
|
license = {text = "Apache-2.0"}
|
|
@@ -53,7 +53,16 @@ class Architecture:
|
|
|
53
53
|
return {s: v for s, v in self.licences.items() if copyleft(v)}
|
|
54
54
|
|
|
55
55
|
def fingerprint(self) -> str:
|
|
56
|
-
|
|
56
|
+
"""Topology and decisions together.
|
|
57
|
+
|
|
58
|
+
Two engagements with the same approach set but different topologies
|
|
59
|
+
build byte-different projects (the boundary code differs), and a
|
|
60
|
+
fingerprint that called them identical was answering a narrower
|
|
61
|
+
question than the one it prints beside."""
|
|
62
|
+
import hashlib
|
|
63
|
+
|
|
64
|
+
payload = f"{self.topology}:{self.decisions.decided_fingerprint()}"
|
|
65
|
+
return hashlib.sha256(payload.encode()).hexdigest()[:16]
|
|
57
66
|
|
|
58
67
|
|
|
59
68
|
def architect(
|
|
@@ -592,6 +592,12 @@ def ask(
|
|
|
592
592
|
continue
|
|
593
593
|
|
|
594
594
|
dimension_entry = registry.dimensions[question.resolves]
|
|
595
|
+
# A multi-valued dimension never enters the answer space (a second
|
|
596
|
+
# value is a peer, not a contradiction), so the space alone would
|
|
597
|
+
# offer this question again immediately -- asked and answered is
|
|
598
|
+
# asked and answered for this session; a later session can add more.
|
|
599
|
+
if dimension_entry.multi_valued or isinstance(answer.value, tuple):
|
|
600
|
+
passed_on.add(question.resolves)
|
|
595
601
|
answered_values = (
|
|
596
602
|
list(answer.value) if isinstance(answer.value, tuple) else [answer.value]
|
|
597
603
|
)
|
|
@@ -1517,9 +1523,15 @@ def build_cmd(
|
|
|
1517
1523
|
]
|
|
1518
1524
|
report = emit(architecture, out, registry=registry,
|
|
1519
1525
|
templates=Path(registry_root) / "templates",
|
|
1520
|
-
|
|
1526
|
+
# The engagement's own root, never the raw argument: a
|
|
1527
|
+
# bare name (`fde build receipts`) resolves through
|
|
1528
|
+
# _engagement, and building the pairs path from the raw
|
|
1529
|
+
# argument silently emitted a project with an empty
|
|
1530
|
+
# golden set while 42 verified pairs sat on disk.
|
|
1531
|
+
pairs_path=engagement.root / "artifacts" / "pairs.jsonl",
|
|
1521
1532
|
waivers=waivers,
|
|
1522
|
-
overrides=applied_overrides
|
|
1533
|
+
overrides=applied_overrides,
|
|
1534
|
+
baseline=engagement.baseline())
|
|
1523
1535
|
except BuildRefused as exc:
|
|
1524
1536
|
typer.echo(f"refused: {exc}", err=True)
|
|
1525
1537
|
raise typer.Exit(1) from exc
|
|
@@ -1554,6 +1566,22 @@ def build_cmd(
|
|
|
1554
1566
|
_write_compliance(Path(out), locale)
|
|
1555
1567
|
|
|
1556
1568
|
typer.echo(f"wrote {out}")
|
|
1569
|
+
# The exam's size belongs in the build receipt: an empty golden set
|
|
1570
|
+
# emitted next to sixty pairs on disk once read as a finished build.
|
|
1571
|
+
counts = {}
|
|
1572
|
+
for layer in ("golden", "edge_case", "adversarial"):
|
|
1573
|
+
layer_path = Path(out) / "evals" / f"{layer}.jsonl"
|
|
1574
|
+
counts[layer] = sum(
|
|
1575
|
+
1 for line in layer_path.read_text().splitlines() if line.strip()
|
|
1576
|
+
) if layer_path.exists() else 0
|
|
1577
|
+
typer.echo(f"evals: {counts['golden']} golden, {counts['edge_case']} edge, "
|
|
1578
|
+
f"{counts['adversarial']} adversarial")
|
|
1579
|
+
if not counts["golden"] and (engagement.root / "artifacts" / "pairs.jsonl").exists():
|
|
1580
|
+
typer.echo(
|
|
1581
|
+
" pairs exist on the engagement but none reached the golden set -- "
|
|
1582
|
+
"mark checked pairs `verified: true` and re-run `fde samples`",
|
|
1583
|
+
err=True,
|
|
1584
|
+
)
|
|
1557
1585
|
# The delivery is finishable, and the finishing move is one command.
|
|
1558
1586
|
holdout_path = engagement.root / "artifacts" / "holdout.jsonl"
|
|
1559
1587
|
hint = f"fde implement {out}"
|
|
@@ -1648,7 +1676,15 @@ def scan_cmd(
|
|
|
1648
1676
|
# costing figure, because model releases move monthly.
|
|
1649
1677
|
from fde.scan import MODEL_GUIDANCE_AS_OF, recommend_local_models
|
|
1650
1678
|
|
|
1651
|
-
|
|
1679
|
+
# The engine choice is a concurrency decision as much as a hardware
|
|
1680
|
+
# one: when the engagement recorded an arrival rate, it flows in.
|
|
1681
|
+
arrival = None
|
|
1682
|
+
if root is not None:
|
|
1683
|
+
try:
|
|
1684
|
+
arrival = _engagement(root).profile.get("arrival_rate")
|
|
1685
|
+
except Exception: # noqa: BLE001 -- a scan without an engagement still scans
|
|
1686
|
+
arrival = None
|
|
1687
|
+
plan = recommend_local_models(hardware, arrival_per_day=arrival)
|
|
1652
1688
|
typer.echo(f"\nlocal models (guidance as of {MODEL_GUIDANCE_AS_OF} -- "
|
|
1653
1689
|
f"releases move monthly, verify before install)")
|
|
1654
1690
|
typer.echo(f" runtime: {plan.runtime} -- {plan.runtime_reason}")
|
|
@@ -111,9 +111,22 @@ def decide_component(
|
|
|
111
111
|
)
|
|
112
112
|
continue
|
|
113
113
|
if not any(holds(c, profile, registry) for c in approach.applies_when):
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
114
|
+
reason = f"nothing here matches {' or '.join(approach.applies_when)}"
|
|
115
|
+
# An unanswered dimension is a different situation from a
|
|
116
|
+
# mismatched one: the reader should know one question could
|
|
117
|
+
# change this rejection, not go looking for a design flaw.
|
|
118
|
+
open_dimensions = sorted({
|
|
119
|
+
dimension
|
|
120
|
+
for condition in approach.applies_when
|
|
121
|
+
for dimension in _referenced(condition)
|
|
122
|
+
if profile.get(dimension) is None
|
|
123
|
+
})
|
|
124
|
+
if open_dimensions:
|
|
125
|
+
reason += (
|
|
126
|
+
f" -- unanswered: {', '.join(open_dimensions)} "
|
|
127
|
+
f"(an answer could admit it)"
|
|
128
|
+
)
|
|
129
|
+
rejected.append(Rejected(approach.id, reason))
|
|
117
130
|
# Not ruled out -- just not ruled in. If its applies conditions
|
|
118
131
|
# reference something unanswered, an answer could still admit it.
|
|
119
132
|
still_askable.append(approach)
|