|
| 1 | +"""Recomposition data model — the Natural Description Build Plan. |
| 2 | +
|
| 3 | +A :class:`BuildPlan` is an ordered sequence of :class:`BuildStep` records that, |
| 4 | +followed in order, reconstruct the system described by a Decomposer output. |
| 5 | +Every step is evidence-grounded (it cites the decomposition part ids and files |
| 6 | +it derives from) and confidence-tagged; steps resting on unresolved assumptions |
| 7 | +carry them explicitly (Part IV: "reconstruction steps that depend on unresolved |
| 8 | +assumptions" must be reported, never silently embedded). |
| 9 | +
|
| 10 | +The Recomposer consumes ONLY the decomposition document — never the raw bundle |
| 11 | +or repository — so this model mirrors what that document can prove. |
| 12 | +""" |
| 13 | +from __future__ import annotations |
| 14 | + |
| 15 | +from dataclasses import dataclass, field |
| 16 | +from typing import Any |
| 17 | + |
| 18 | +# Canonical construction phases (Part III). The scheduler may pull a step to an |
| 19 | +# earlier phase than its nominal one when dependency evidence forces it (e.g. a |
| 20 | +# cycle group spanning core and infrastructure must be built together); it never |
| 21 | +# pushes a step later than its dependents. |
| 22 | +PHASES: list[tuple[int, str, str]] = [ |
| 23 | + (1, "skeleton", "Establish project skeleton"), |
| 24 | + (2, "environment", "Configure package/build/runtime environment"), |
| 25 | + (3, "domain_data", "Define core domain/data model"), |
| 26 | + (4, "contracts", "Define internal contracts/interfaces"), |
| 27 | + (5, "core_logic", "Implement core logic"), |
| 28 | + (6, "adapters_infrastructure", "Implement adapters/infrastructure"), |
| 29 | + (7, "delivery_surfaces", "Implement APIs/CLIs/jobs/events"), |
| 30 | + (8, "persistence", "Implement persistence and migrations"), |
| 31 | + (9, "configuration_deployment", "Implement configuration and deployment"), |
| 32 | + (10, "tests_fixtures", "Implement tests and fixtures"), |
| 33 | + (11, "validation", "Validate full-system behavior"), |
| 34 | + (12, "documentation", "Document usage and extension points"), |
| 35 | +] |
| 36 | +PHASE_TITLE: dict[int, str] = {n: title for n, _, title in PHASES} |
| 37 | +PHASE_KEY: dict[int, str] = {n: key for n, key, _ in PHASES} |
| 38 | + |
| 39 | + |
| 40 | +@dataclass |
| 41 | +class BuildStep: |
| 42 | + number: int |
| 43 | + phase: int # 1..12, index into PHASES |
| 44 | + goal: str |
| 45 | + rationale: str # construction intent: why now, why this shape |
| 46 | + requires: list[int] = field(default_factory=list) # earlier step numbers |
| 47 | + creates: list[str] = field(default_factory=list) # files/components to create |
| 48 | + contracts: list[str] = field(default_factory=list) # interfaces/symbols to define |
| 49 | + dependencies_introduced: list[str] = field(default_factory=list) |
| 50 | + tests_required: list[str] = field(default_factory=list) |
| 51 | + evidence: list[str] = field(default_factory=list) # part ids + signals |
| 52 | + expected_result: str = "" |
| 53 | + confidence: str = "probable" |
| 54 | + assumptions: list[str] = field(default_factory=list) # unresolved assumptions |
| 55 | + parts: list[str] = field(default_factory=list) # decomposition part ids realized |
| 56 | + |
| 57 | + def to_dict(self) -> dict[str, Any]: |
| 58 | + return { |
| 59 | + "step": self.number, |
| 60 | + "phase": self.phase, |
| 61 | + "phase_title": PHASE_TITLE.get(self.phase, "?"), |
| 62 | + "goal": self.goal, |
| 63 | + "rationale": self.rationale, |
| 64 | + "requires_steps": list(self.requires), |
| 65 | + "creates": list(self.creates), |
| 66 | + "contracts": list(self.contracts), |
| 67 | + "dependencies_introduced": list(self.dependencies_introduced), |
| 68 | + "tests_required": list(self.tests_required), |
| 69 | + "evidence": list(self.evidence), |
| 70 | + "expected_result": self.expected_result, |
| 71 | + "confidence": self.confidence, |
| 72 | + "assumptions": list(self.assumptions), |
| 73 | + "parts": list(self.parts), |
| 74 | + } |
| 75 | + |
| 76 | + |
| 77 | +@dataclass |
| 78 | +class BuildPlan: |
| 79 | + repository: dict[str, Any] # copied from the decomposition header |
| 80 | + architecture_intent: dict[str, Any] # style + hypotheses the rebuild should honor |
| 81 | + steps: list[BuildStep] = field(default_factory=list) |
| 82 | + skipped_phases: list[dict[str, str]] = field(default_factory=list) |
| 83 | + open_assumptions: list[str] = field(default_factory=list) |
| 84 | + provenance: dict[str, Any] = field(default_factory=dict) |
| 85 | + |
| 86 | + def to_dict(self) -> dict[str, Any]: |
| 87 | + return { |
| 88 | + "repository": self.repository, |
| 89 | + "architecture_intent": self.architecture_intent, |
| 90 | + "steps": [s.to_dict() for s in self.steps], |
| 91 | + "skipped_phases": list(self.skipped_phases), |
| 92 | + "open_assumptions": list(self.open_assumptions), |
| 93 | + "provenance": self.provenance, |
| 94 | + } |
0 commit comments