fde-framework 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fde/__init__.py +3 -0
- fde/architect.py +152 -0
- fde/cli.py +2107 -0
- fde/costing.py +292 -0
- fde/decide.py +297 -0
- fde/decompose.py +54 -0
- fde/deploy.py +371 -0
- fde/emit.py +1309 -0
- fde/evolution.py +265 -0
- fde/factlog.py +369 -0
- fde/framework/approaches/ansible-playbook.md +22 -0
- fde/framework/approaches/assisted-deterministic.md +37 -0
- fde/framework/approaches/audit-only.md +23 -0
- fde/framework/approaches/boundary-and-audit.md +18 -0
- fde/framework/approaches/cascade.md +32 -0
- fde/framework/approaches/classical-ml.md +21 -0
- fde/framework/approaches/compose.md +18 -0
- fde/framework/approaches/decision-log.md +21 -0
- fde/framework/approaches/deterministic-masking.md +18 -0
- fde/framework/approaches/deterministic.md +25 -0
- fde/framework/approaches/direct-call.md +10 -0
- fde/framework/approaches/episodic-store.md +17 -0
- fde/framework/approaches/explainability-record.md +14 -0
- fde/framework/approaches/field-match.md +15 -0
- fde/framework/approaches/finetune.md +29 -0
- fde/framework/approaches/fixed-sequence.md +19 -0
- fde/framework/approaches/gitops.md +18 -0
- fde/framework/approaches/governed-tools.md +18 -0
- fde/framework/approaches/graph-retrieval.md +22 -0
- fde/framework/approaches/judged.md +15 -0
- fde/framework/approaches/keyword-search.md +11 -0
- fde/framework/approaches/kubernetes-manifests.md +19 -0
- fde/framework/approaches/labelled-metrics.md +14 -0
- fde/framework/approaches/llm-extraction.md +26 -0
- fde/framework/approaches/llm-scrubbing.md +20 -0
- fde/framework/approaches/llm.md +23 -0
- fde/framework/approaches/local-embedding.md +28 -0
- fde/framework/approaches/managed-api.md +49 -0
- fde/framework/approaches/managed-embedding.md +22 -0
- fde/framework/approaches/manual-runbook.md +32 -0
- fde/framework/approaches/model-planner.md +19 -0
- fde/framework/approaches/ocr-pipeline.md +13 -0
- fde/framework/approaches/optimisation-reasoning.md +30 -0
- fde/framework/approaches/optimisation.md +19 -0
- fde/framework/approaches/passthrough.md +11 -0
- fde/framework/approaches/role-scoped-authority.md +19 -0
- fde/framework/approaches/segmentation.md +29 -0
- fde/framework/approaches/self-hosted.md +38 -0
- fde/framework/approaches/serverless-gpu.md +27 -0
- fde/framework/approaches/speech-transcription.md +21 -0
- fde/framework/approaches/structured-logs.md +11 -0
- fde/framework/approaches/systemd-unit.md +30 -0
- fde/framework/approaches/terraform-module.md +22 -0
- fde/framework/approaches/text-extraction.md +14 -0
- fde/framework/approaches/traced.md +24 -0
- fde/framework/approaches/vector-search.md +17 -0
- fde/framework/approaches/video-ingestion.md +16 -0
- fde/framework/approaches/windowed-ingestion.md +25 -0
- fde/framework/approaches/working-state.md +13 -0
- fde/framework/cases/churn-scoring.md +45 -0
- fde/framework/cases/route-planning.md +44 -0
- fde/framework/cases/structured-extraction.md +48 -0
- fde/framework/cases/studio-style.md +46 -0
- fde/framework/components/accountability.md +20 -0
- fde/framework/components/deployment.md +19 -0
- fde/framework/components/embedding.md +23 -0
- fde/framework/components/evaluation.md +13 -0
- fde/framework/components/governance.md +19 -0
- fde/framework/components/integration.md +13 -0
- fde/framework/components/memory.md +21 -0
- fde/framework/components/observability.md +13 -0
- fde/framework/components/perception.md +15 -0
- fde/framework/components/planning.md +15 -0
- fde/framework/components/provisioning.md +17 -0
- fde/framework/components/reasoning.md +20 -0
- fde/framework/components/redaction.md +18 -0
- fde/framework/components/representation.md +13 -0
- fde/framework/components/retrieval.md +13 -0
- fde/framework/components/serving.md +20 -0
- fde/framework/dimensions/accelerator.md +29 -0
- fde/framework/dimensions/access_model.md +25 -0
- fde/framework/dimensions/arrival_rate.md +19 -0
- fde/framework/dimensions/availability_target.md +23 -0
- fde/framework/dimensions/cheap_path_coverage.md +21 -0
- fde/framework/dimensions/confidence_calibrated.md +30 -0
- fde/framework/dimensions/container_competence.md +22 -0
- fde/framework/dimensions/corpus_size.md +13 -0
- fde/framework/dimensions/data_residency.md +36 -0
- fde/framework/dimensions/environment_lifetime.md +19 -0
- fde/framework/dimensions/existing_cluster.md +22 -0
- fde/framework/dimensions/existing_iac_tool.md +25 -0
- fde/framework/dimensions/external_systems.md +15 -0
- fde/framework/dimensions/hosting.md +45 -0
- fde/framework/dimensions/human_waiting.md +41 -0
- fde/framework/dimensions/input_format.md +29 -0
- fde/framework/dimensions/interpretability_required.md +24 -0
- fde/framework/dimensions/labelled_count.md +15 -0
- fde/framework/dimensions/latency_budget_ms.md +16 -0
- fde/framework/dimensions/licence_posture.md +28 -0
- fde/framework/dimensions/operates_after_handover.md +25 -0
- fde/framework/dimensions/output_shape.md +29 -0
- fde/framework/dimensions/provisioning_api.md +18 -0
- fde/framework/dimensions/query_pattern.md +25 -0
- fde/framework/dimensions/recall_span.md +22 -0
- fde/framework/dimensions/sensitivity_present.md +22 -0
- fde/framework/interfaces/Generator.md +5 -0
- fde/framework/interfaces/Guard.md +5 -0
- fde/framework/interfaces/Mapper.md +5 -0
- fde/framework/interfaces/ModelServer.md +5 -0
- fde/framework/interfaces/Parser.md +5 -0
- fde/framework/interfaces/Planner.md +5 -0
- fde/framework/interfaces/Retriever.md +5 -0
- fde/framework/interfaces/Scorer.md +5 -0
- fde/framework/interfaces/Store.md +5 -0
- fde/framework/interfaces/ToolBoundary.md +5 -0
- fde/framework/interfaces/Tracer.md +5 -0
- fde/framework/locales/eu-gdpr.md +51 -0
- fde/framework/locales/in-dpdp.md +46 -0
- fde/framework/patterns/ansible-playbook.md +9 -0
- fde/framework/patterns/assisted-deterministic.md +11 -0
- fde/framework/patterns/audit-only.md +9 -0
- fde/framework/patterns/boundary-and-audit.md +12 -0
- fde/framework/patterns/cascade-reasoning.md +10 -0
- fde/framework/patterns/cascade-representation.md +10 -0
- fde/framework/patterns/cascade-retrieval.md +10 -0
- fde/framework/patterns/classical-ml-reasoning.md +15 -0
- fde/framework/patterns/classical-ml.md +13 -0
- fde/framework/patterns/compose.md +9 -0
- fde/framework/patterns/decision-log.md +9 -0
- fde/framework/patterns/deterministic-masking.md +9 -0
- fde/framework/patterns/deterministic.md +12 -0
- fde/framework/patterns/direct-call.md +12 -0
- fde/framework/patterns/episodic-store.md +13 -0
- fde/framework/patterns/explainability-record.md +9 -0
- fde/framework/patterns/field-match.md +12 -0
- fde/framework/patterns/finetune-representation.md +14 -0
- fde/framework/patterns/finetune.md +12 -0
- fde/framework/patterns/fixed-sequence.md +12 -0
- fde/framework/patterns/gitops.md +9 -0
- fde/framework/patterns/governed-tools.md +13 -0
- fde/framework/patterns/graph-retrieval.md +14 -0
- fde/framework/patterns/judged.md +14 -0
- fde/framework/patterns/keyword-search.md +12 -0
- fde/framework/patterns/kubernetes-manifests.md +9 -0
- fde/framework/patterns/labelled-metrics.md +13 -0
- fde/framework/patterns/llm-representation.md +17 -0
- fde/framework/patterns/llm-scrubbing.md +9 -0
- fde/framework/patterns/llm.md +12 -0
- fde/framework/patterns/local-embedding.md +9 -0
- fde/framework/patterns/managed-api.md +12 -0
- fde/framework/patterns/managed-embedding.md +9 -0
- fde/framework/patterns/manual-runbook.md +9 -0
- fde/framework/patterns/model-planner.md +13 -0
- fde/framework/patterns/ocr-pipeline.md +13 -0
- fde/framework/patterns/optimisation-reasoning.md +15 -0
- fde/framework/patterns/optimisation.md +13 -0
- fde/framework/patterns/passthrough.md +12 -0
- fde/framework/patterns/role-scoped-authority.md +9 -0
- fde/framework/patterns/segmentation.md +12 -0
- fde/framework/patterns/self-hosted.md +14 -0
- fde/framework/patterns/serverless-gpu.md +12 -0
- fde/framework/patterns/speech-transcription.md +10 -0
- fde/framework/patterns/structured-logs.md +12 -0
- fde/framework/patterns/systemd-unit.md +9 -0
- fde/framework/patterns/terraform-module.md +9 -0
- fde/framework/patterns/text-extraction.md +12 -0
- fde/framework/patterns/traced.md +13 -0
- fde/framework/patterns/vector-search.md +14 -0
- fde/framework/patterns/video-ingestion.md +9 -0
- fde/framework/patterns/windowed-ingestion.md +12 -0
- fde/framework/patterns/working-state.md +12 -0
- fde/framework/stacks/langgraph.md +9 -0
- fde/framework/stacks/local-judge.md +9 -0
- fde/framework/stacks/mcp.md +9 -0
- fde/framework/stacks/ollama.md +19 -0
- fde/framework/stacks/openai-judge.md +9 -0
- fde/framework/stacks/opentelemetry.md +9 -0
- fde/framework/stacks/ortools.md +9 -0
- fde/framework/stacks/pgvector.md +9 -0
- fde/framework/stacks/plain-python.md +9 -0
- fde/framework/stacks/qdrant.md +9 -0
- fde/framework/stacks/tesseract.md +9 -0
- fde/framework/stacks/vllm.md +9 -0
- fde/framework/stacks/whisper.md +15 -0
- fde/framework/stacks/xgboost.md +9 -0
- fde/framework/templates/accountability/decision-log.plain.py.j2 +64 -0
- fde/framework/templates/accountability/explainability-record.plain.py.j2 +90 -0
- fde/framework/templates/deployment/compose.plain.py.j2 +36 -0
- fde/framework/templates/deployment/kubernetes-manifests.plain.py.j2 +36 -0
- fde/framework/templates/deployment/systemd-unit.plain.py.j2 +36 -0
- fde/framework/templates/embedding/local-embedding.plain.py.j2 +71 -0
- fde/framework/templates/embedding/managed-embedding.plain.py.j2 +76 -0
- fde/framework/templates/evaluation/field-match.plain.py.j2 +146 -0
- fde/framework/templates/evaluation/judged.local-judge.py.j2 +100 -0
- fde/framework/templates/evaluation/judged.openai-judge.py.j2 +70 -0
- fde/framework/templates/evaluation/judged.plain.py.j2 +89 -0
- fde/framework/templates/evaluation/labelled-metrics.plain.py.j2 +64 -0
- fde/framework/templates/evaluation/labelled-metrics.xgboost.py.j2 +72 -0
- fde/framework/templates/governance/audit-only.plain.py.j2 +98 -0
- fde/framework/templates/governance/boundary-and-audit.plain.py.j2 +142 -0
- fde/framework/templates/governance/role-scoped-authority.plain.py.j2 +63 -0
- fde/framework/templates/integration/direct-call.plain.py.j2 +63 -0
- fde/framework/templates/integration/governed-tools.mcp.py.j2 +124 -0
- fde/framework/templates/integration/governed-tools.plain.py.j2 +153 -0
- fde/framework/templates/memory/episodic-store.pgvector.py.j2 +118 -0
- fde/framework/templates/memory/episodic-store.plain.py.j2 +147 -0
- fde/framework/templates/memory/working-state.plain.py.j2 +48 -0
- fde/framework/templates/observability/structured-logs.plain.py.j2 +61 -0
- fde/framework/templates/observability/traced.opentelemetry.py.j2 +65 -0
- fde/framework/templates/observability/traced.plain.py.j2 +132 -0
- fde/framework/templates/perception/ocr-pipeline.plain.py.j2 +71 -0
- fde/framework/templates/perception/ocr-pipeline.tesseract.py.j2 +80 -0
- fde/framework/templates/perception/passthrough.plain.py.j2 +41 -0
- fde/framework/templates/perception/speech-transcription.plain.py.j2 +37 -0
- fde/framework/templates/perception/speech-transcription.whisper.py.j2 +39 -0
- fde/framework/templates/perception/text-extraction.plain.py.j2 +88 -0
- fde/framework/templates/perception/video-ingestion.plain.py.j2 +35 -0
- fde/framework/templates/perception/windowed-ingestion.plain.py.j2 +69 -0
- fde/framework/templates/planning/fixed-sequence.plain.py.j2 +46 -0
- fde/framework/templates/planning/model-planner.langgraph.py.j2 +89 -0
- fde/framework/templates/planning/model-planner.plain.py.j2 +82 -0
- fde/framework/templates/planning/optimisation.ortools.py.j2 +90 -0
- fde/framework/templates/planning/optimisation.plain.py.j2 +71 -0
- fde/framework/templates/provisioning/ansible-playbook.plain.py.j2 +29 -0
- fde/framework/templates/provisioning/gitops.plain.py.j2 +29 -0
- fde/framework/templates/provisioning/manual-runbook.plain.py.j2 +29 -0
- fde/framework/templates/provisioning/terraform-module.plain.py.j2 +29 -0
- fde/framework/templates/reasoning/cascade.plain.py.j2 +86 -0
- fde/framework/templates/reasoning/classical-ml.plain.py.j2 +74 -0
- fde/framework/templates/reasoning/classical-ml.xgboost.py.j2 +104 -0
- fde/framework/templates/reasoning/finetune.plain.py.j2 +73 -0
- fde/framework/templates/reasoning/llm.plain.py.j2 +114 -0
- fde/framework/templates/reasoning/optimisation.ortools.py.j2 +90 -0
- fde/framework/templates/reasoning/optimisation.plain.py.j2 +58 -0
- fde/framework/templates/redaction/deterministic-masking.plain.py.j2 +44 -0
- fde/framework/templates/redaction/llm-scrubbing.plain.py.j2 +40 -0
- fde/framework/templates/representation/assisted.plain.py.j2 +86 -0
- fde/framework/templates/representation/cascade.plain.py.j2 +119 -0
- fde/framework/templates/representation/classical-ml.plain.py.j2 +74 -0
- fde/framework/templates/representation/classical-ml.xgboost.py.j2 +104 -0
- fde/framework/templates/representation/deterministic.plain.py.j2 +101 -0
- fde/framework/templates/representation/finetune.plain.py.j2 +68 -0
- fde/framework/templates/representation/llm.plain.py.j2 +94 -0
- fde/framework/templates/representation/segmentation.plain.py.j2 +68 -0
- fde/framework/templates/retrieval/cascade.plain.py.j2 +86 -0
- fde/framework/templates/retrieval/graph-retrieval.pgvector.py.j2 +88 -0
- fde/framework/templates/retrieval/graph-retrieval.plain.py.j2 +74 -0
- fde/framework/templates/retrieval/graph-retrieval.qdrant.py.j2 +71 -0
- fde/framework/templates/retrieval/keyword-search.plain.py.j2 +104 -0
- fde/framework/templates/retrieval/vector-search.pgvector.py.j2 +100 -0
- fde/framework/templates/retrieval/vector-search.plain.py.j2 +84 -0
- fde/framework/templates/retrieval/vector-search.qdrant.py.j2 +60 -0
- fde/framework/templates/serving/managed-api.plain.py.j2 +74 -0
- fde/framework/templates/serving/self-hosted.ollama.py.j2 +47 -0
- fde/framework/templates/serving/self-hosted.plain.py.j2 +117 -0
- fde/framework/templates/serving/self-hosted.vllm.py.j2 +77 -0
- fde/framework/templates/serving/serverless-gpu.plain.py.j2 +62 -0
- fde/gates.py +480 -0
- fde/graph.py +435 -0
- fde/implement.py +250 -0
- fde/intake/__init__.py +0 -0
- fde/intake/answers.py +154 -0
- fde/intake/documents.py +121 -0
- fde/intake/interview.py +218 -0
- fde/intake/llm_reader.py +336 -0
- fde/intake/prose.py +387 -0
- fde/intake/samples.py +369 -0
- fde/models/__init__.py +0 -0
- fde/models/base.py +86 -0
- fde/models/fact.py +37 -0
- fde/models/profile.py +159 -0
- fde/models/respondent.py +34 -0
- fde/models/schema.py +430 -0
- fde/moves.py +136 -0
- fde/ops.py +349 -0
- fde/predicate.py +106 -0
- fde/realization.py +109 -0
- fde/registry.py +162 -0
- fde/scan.py +479 -0
- fde/space.py +172 -0
- fde/workflow.py +233 -0
- fde_framework-0.1.0.dist-info/METADATA +449 -0
- fde_framework-0.1.0.dist-info/RECORD +286 -0
- fde_framework-0.1.0.dist-info/WHEEL +4 -0
- fde_framework-0.1.0.dist-info/entry_points.txt +2 -0
- fde_framework-0.1.0.dist-info/licenses/LICENSE +202 -0
fde/__init__.py
ADDED
fde/architect.py
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"""Everything decided, in one object.
|
|
2
|
+
|
|
3
|
+
`architect` is the join: a profile in, and out comes the component graph, the
|
|
4
|
+
decisions, the workflow after the moves have been applied, and the implementation
|
|
5
|
+
chosen for each component. It is the thing `emit` writes and the thing a client
|
|
6
|
+
reviews, and both need the same information.
|
|
7
|
+
|
|
8
|
+
Assumptions and disagreements travel with it deliberately. A design that arrives
|
|
9
|
+
without them looks more certain than it is, and the questions nobody answered
|
|
10
|
+
are exactly what a reader should check.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from dataclasses import dataclass, field
|
|
16
|
+
|
|
17
|
+
from fde.decide import Decision, Decisions, Rejected, base_component, decide_all
|
|
18
|
+
from fde.decompose import ComponentGraph, decompose
|
|
19
|
+
from fde.graph import TOPOLOGY_DIMENSION
|
|
20
|
+
from fde.models.profile import Disagreement, Profile
|
|
21
|
+
from fde.moves import apply_all
|
|
22
|
+
from fde.realization import (
|
|
23
|
+
NoRealization,
|
|
24
|
+
UnsupportedTopology,
|
|
25
|
+
copyleft,
|
|
26
|
+
realization_for,
|
|
27
|
+
)
|
|
28
|
+
from fde.registry import Registry
|
|
29
|
+
from fde.workflow import WorkflowGraph, build_graph
|
|
30
|
+
|
|
31
|
+
DEFAULT_TOPOLOGY = "customer-vpc"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass
|
|
35
|
+
class Architecture:
|
|
36
|
+
components: ComponentGraph
|
|
37
|
+
decisions: Decisions
|
|
38
|
+
graph: WorkflowGraph
|
|
39
|
+
topology: str
|
|
40
|
+
realizations: dict[str, object] = field(default_factory=dict)
|
|
41
|
+
licences: dict[str, str] = field(default_factory=dict)
|
|
42
|
+
assumptions: list[str] = field(default_factory=list)
|
|
43
|
+
disagreements: list[Disagreement] = field(default_factory=list)
|
|
44
|
+
unrealizable: dict[str, str] = field(default_factory=dict)
|
|
45
|
+
already_running: set[str] = field(default_factory=set)
|
|
46
|
+
|
|
47
|
+
# What was known when this was decided. Carried so the documents can quote
|
|
48
|
+
# a stated budget rather than reconstruct it from a rationale.
|
|
49
|
+
values: dict[str, object] = field(default_factory=dict)
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def copyleft_licences(self) -> dict[str, str]:
|
|
53
|
+
return {s: v for s, v in self.licences.items() if copyleft(v)}
|
|
54
|
+
|
|
55
|
+
def fingerprint(self) -> str:
|
|
56
|
+
return self.decisions.decided_fingerprint()
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def architect(
|
|
60
|
+
profile: Profile,
|
|
61
|
+
registry: Registry,
|
|
62
|
+
already_running: set[str] | None = None,
|
|
63
|
+
overrides: dict[str, dict] | None = None,
|
|
64
|
+
) -> Architecture:
|
|
65
|
+
components = decompose(profile, registry)
|
|
66
|
+
values = profile.values()
|
|
67
|
+
decisions = decide_all(values, registry, components=list(components.components))
|
|
68
|
+
_apply_overrides(decisions, overrides or {})
|
|
69
|
+
graph = apply_all(build_graph(decisions, registry, values=values))
|
|
70
|
+
topology = values.get(TOPOLOGY_DIMENSION) or DEFAULT_TOPOLOGY
|
|
71
|
+
|
|
72
|
+
realizations, licences, unrealizable = {}, {}, {}
|
|
73
|
+
for component, decision in decisions.decided().items():
|
|
74
|
+
try:
|
|
75
|
+
chosen = realization_for(
|
|
76
|
+
decision.approach, base_component(component), registry,
|
|
77
|
+
topology, already_running,
|
|
78
|
+
)
|
|
79
|
+
except (NoRealization, UnsupportedTopology) as exc:
|
|
80
|
+
unrealizable[component] = str(exc)
|
|
81
|
+
# The pipeline must not reference a class the module does not
|
|
82
|
+
# define. Unrealizable behaves like undecided: the module exists,
|
|
83
|
+
# says why, and raises on use.
|
|
84
|
+
if component in graph.nodes:
|
|
85
|
+
graph.nodes[component].unfilled = True
|
|
86
|
+
continue
|
|
87
|
+
realizations[component] = chosen
|
|
88
|
+
licences[chosen.stack] = registry.stacks[chosen.stack].licence
|
|
89
|
+
|
|
90
|
+
return Architecture(
|
|
91
|
+
already_running=set(already_running or ()),
|
|
92
|
+
components=components,
|
|
93
|
+
decisions=decisions,
|
|
94
|
+
graph=graph,
|
|
95
|
+
topology=topology,
|
|
96
|
+
realizations=realizations,
|
|
97
|
+
licences=licences,
|
|
98
|
+
assumptions=_assumptions(profile, registry),
|
|
99
|
+
disagreements=profile.disagreements(),
|
|
100
|
+
unrealizable=unrealizable,
|
|
101
|
+
values=dict(values),
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _apply_overrides(decisions: Decisions, overrides: dict[str, dict]) -> None:
|
|
106
|
+
"""The FDE's recorded choice replaces the recommendation.
|
|
107
|
+
|
|
108
|
+
An override that is written down and then ignored is worse than none:
|
|
109
|
+
the promise "your choice is honoured" was made at record time, and the
|
|
110
|
+
next `architect` run silently reverting it breaks both the promise and
|
|
111
|
+
the signal -- nobody can tell an honoured override from a forgotten one.
|
|
112
|
+
"""
|
|
113
|
+
for component, override in overrides.items():
|
|
114
|
+
# A fanned component holds instance keys (perception:images ...).
|
|
115
|
+
# An override of the base name applies to every instance -- the
|
|
116
|
+
# promise "your choice is honoured" does not get to lapse because
|
|
117
|
+
# the engagement turned out to be multi-modal -- and an instance
|
|
118
|
+
# key targets exactly one. A base override that matches nothing is
|
|
119
|
+
# the silent-drop this comment used to describe; it is now
|
|
120
|
+
# impossible for any component that decided at all.
|
|
121
|
+
targets = [
|
|
122
|
+
key for key in decisions
|
|
123
|
+
if key == component or key.startswith(component + ":")
|
|
124
|
+
]
|
|
125
|
+
for key in targets:
|
|
126
|
+
previous = decisions[key]
|
|
127
|
+
decisions[key] = Decision(
|
|
128
|
+
component=key,
|
|
129
|
+
approach=override["chosen"],
|
|
130
|
+
rationale=f"overridden on site: "
|
|
131
|
+
f"{override.get('because', 'no reason recorded')}",
|
|
132
|
+
rejected=(
|
|
133
|
+
[Rejected(id=previous.approach,
|
|
134
|
+
reason="recommended, overridden on site")]
|
|
135
|
+
if previous.approach and previous.approach != override["chosen"]
|
|
136
|
+
else []
|
|
137
|
+
),
|
|
138
|
+
considered=previous.considered,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def _assumptions(profile: Profile, registry: Registry) -> list[str]:
|
|
143
|
+
"""Every dimension a decision could have used and nobody answered.
|
|
144
|
+
|
|
145
|
+
Stated rather than defaulted. A design that hides what it guessed reads as
|
|
146
|
+
more certain than it is, and the guesses are the first thing worth checking.
|
|
147
|
+
"""
|
|
148
|
+
return [
|
|
149
|
+
f"{dimension}: not stated, so nothing was decided on it"
|
|
150
|
+
for dimension in sorted(registry.dimensions)
|
|
151
|
+
if not profile.resolved(dimension)
|
|
152
|
+
]
|