Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .agents/logs/2026-07-31.jsonl
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
{"agent": "build", "session_id": "build-20260731-finance-split-001", "triggered_by": "feature-flow", "started_at": "2026-07-31T16:00:00Z", "timestamp": "2026-07-31T17:45:00Z", "duration_ms": 6300000, "skills_loaded": ["code-generation", "refactoring", "template-application"], "findings": [{"id": "FIND-001", "description": "Moved copy of total_return_summary dropped the purchase_price key from its return dict, breaking test_dict_keys_present — restored the key to match the original contract", "actionable": true, "manual_review_needed": false, "severity": "defect"}, {"id": "FIND-002", "description": "after_tax_irr in taxes.py had a local import of irr from utils that was unused (function reimplements npf.irr inline) — removed per ruff F401", "actionable": true, "manual_review_needed": false, "severity": "defect"}, {"id": "FIND-003", "description": "tests/test_underwriting_score.py still tested the deleted pure score_listing_v2 (audit finding #2); kept one_percent_rule/gross_rent_multiplier primitive tests, deleted TestScoreListingV2 since production score lives only in core/services/scoring.py (covered by core/tests/test_scoring_v2.py)", "actionable": true, "manual_review_needed": false, "severity": "defect"}, {"id": "FIND-004", "description": "Service-layer duplicate calculate_noi in core/services/property_service.py was exported but imported by no production code — deleted function, export, and its test file", "actionable": true, "manual_review_needed": false, "severity": "defect"}, {"id": "FIND-005", "description": "Dual-pipeline investigation: Django (PipelineAsset/PipelineProperty + core/services/pipeline.py) is the load-bearing pipeline; the pydantic prei FastAPI router, CLI, and orchestrator are not mounted in any Django URLconf/INSTALLED_APPS/docker-compose; only core/views/__init__.py couples to prei (get_state_landlord_score + lazy DiscoveryProcessor/BatchScreeningProcessor/discover_from_all for the Growth Explorer bridge). Full removal of pydantic state machine requires PM sign-off", "actionable": false, "manual_review_needed": true, "severity": "note"}, {"id": "FIND-006", "description": "Re-export backfill from utils.py was unnecessary: after updating all 17 importers, no remaining importer pulls a moved name from investor_app.finance.utils; keeping the monolith aliases would defeat the split", "actionable": false, "manual_review_needed": false, "severity": "note"}, {"id": "FIND-007", "description": "Pre-existing mypy error in tests/acceptance/conftest.py:69 (no-any-return) unrelated to this change — file unmodified", "actionable": false, "manual_review_needed": false, "severity": "note"}], "decision": "implemented", "blockers": [], "pr": null}
{"agent": "build", "session_id": "build-20260731-pydantic-django-consolidation-001", "triggered_by": "feature-flow", "started_at": "2026-07-31T09:00:00Z", "timestamp": "2026-07-31T10:04:32Z", "duration_ms": 3872000, "skills_loaded": ["code-generation", "refactoring", "template-application", "governance-enforcement"], "findings": [{"id": "FIND-001", "description": "Offer math ported to Decimal in core/services/offer.py with OfferInput.__post_init__ validation, resolving LIMIT-21; old tests using model_copy rewritten with dataclasses.replace and Decimal equality", "actionable": true, "manual_review_needed": false, "severity": "defect"}, {"id": "FIND-002", "description": "New dataclasses are pydantic-free so coercion must be explicit: DiscoverySanitizer.transform_input now applies _coerce_float/_coerce_beds/_coerce_baths/_coerce_sqft/_coerce_year; fixed 5 test failures", "actionable": true, "manual_review_needed": false, "severity": "defect"}, {"id": "FIND-003", "description": "prei/integrations/landlord_data.py moved to core/services/landlord_data.py; core/views/__init__.py:50 import updated", "actionable": true, "manual_review_needed": false, "severity": "defect"}, {"id": "FIND-004", "description": "pydantic retained in requirements.txt because tests/acceptance/{schemas,test_api}.py still import it; fastapi/uvicorn/click removed with no remaining consumers", "actionable": true, "manual_review_needed": false, "severity": "note"}, {"id": "FIND-005", "description": "ghcr.io/paruff/prei docker image is the Django web image, not a separate FastAPI/CLI surface; docker-compose/ZAP refs out of scope for this plan", "actionable": false, "manual_review_needed": false, "severity": "note"}, {"id": "FIND-006", "description": "mypy has 2 pre-existing errors unrelated to this work: tests/acceptance/conftest.py:69 (no-any-return) and tests_bdd/conftest.py:31 (__init__ misc); left untouched", "actionable": false, "manual_review_needed": true, "severity": "note"}, {"id": "FIND-007", "description": "Single remaining prei.pipeline reference is a logger namespace string in core/services/pipeline.py, not an import", "actionable": false, "manual_review_needed": false, "severity": "note"}], "decision": "Approved plan executed in full: prei package deleted, services ported to core/services with Decimal offer math, both view bridges rewritten, tests migrated, deps trimmed, docs updated. Full suite green (1791 passed).", "blockers": []}
41 changes: 41 additions & 0 deletions .agents/plans/pydantic-to-django/dependency-graph.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"skill": "plan",
"status": "pass",
"nodes": ["TASK-01", "TASK-02", "TASK-03", "TASK-04", "TASK-05", "TASK-06", "TASK-07", "TASK-08", "TASK-09", "TASK-10", "TASK-11"],
"edges": [
["TASK-02", "TASK-04"],
["TASK-01", "TASK-05"],
["TASK-02", "TASK-05"],
["TASK-04", "TASK-05"],
["TASK-01", "TASK-06"],
["TASK-02", "TASK-06"],
["TASK-04", "TASK-06"],
["TASK-01", "TASK-07"],
["TASK-02", "TASK-07"],
["TASK-03", "TASK-07"],
["TASK-04", "TASK-07"],
["TASK-05", "TASK-08"],
["TASK-06", "TASK-08"],
["TASK-07", "TASK-08"],
["TASK-07", "TASK-09"],
["TASK-08", "TASK-10"],
["TASK-09", "TASK-10"],
["TASK-10", "TASK-11"]
],
"notes": {
"parallel_waves": {
"wave_1": ["TASK-01", "TASK-02", "TASK-03"],
"wave_2": ["TASK-04", "TASK-07"],
"wave_3": ["TASK-05", "TASK-06", "TASK-09"],
"wave_4": ["TASK-08"],
"wave_5": ["TASK-10"],
"wave_6": ["TASK-11"]
},
"critical_path": ["TASK-02", "TASK-04", "TASK-05", "TASK-08", "TASK-10", "TASK-11"],
"bottlenecks": [
"TASK-05/TASK-06 both touch core/views/__init__.py (~5,000 LOC file) — high merge-conflict risk if run in parallel; run TASK-05 before TASK-06",
"TASK-08 and TASK-10 are large deletion tasks (1,100 + 2,100 lines) exceeding the 400-line guidance — acceptable because pure deletions of dead code are low-risk; split per-file if reviewers object"
],
"pm_signoff_gate": "TASK-08 through TASK-11 (deletion of PropertyAsset/StageLog/FastAPI/CLI, engine, orchestrator, sources) require PM sign-off per user directive — plan pending approval for those tasks."
}
}
25 changes: 25 additions & 0 deletions .agents/plans/pydantic-to-django/effort-estimates.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"skill": "plan",
"status": "pass",
"estimates": {
"TASK-01": {"task": "Port screening evaluator + thresholds to core/services/screening.py", "lines": 160, "complexity": "low", "risk": "low", "justification": "Pure function + dataclass port; existing prei test suite covers behavior"},
"TASK-02": {"task": "Port DiscoverySanitizer to core/services/discovery.py", "lines": 130, "complexity": "low", "risk": "low", "justification": "Pure normalization; pydantic model becomes dataclass/dict"},
"TASK-03": {"task": "Port underwriting solver to core/services/underwriting.py", "lines": 150, "complexity": "low", "risk": "low", "justification": "Already Decimal-based; only BaseModel->dataclass swap"},
"TASK-04": {"task": "Port DiscoveryProcessor to Django model layer", "lines": 120, "complexity": "medium", "risk": "medium", "justification": "First Django-model write path; dedup semantics must match address_hash rule"},
"TASK-05": {"task": "Rewrite Growth Explorer bridge (~line 1235)", "lines": 140, "complexity": "high", "risk": "high", "justification": "Touches 5,000-LOC view file; behavior must stay identical; highest regression surface"},
"TASK-06": {"task": "Rewrite vrm_properties_list run_pipeline bridge (~line 3227)", "lines": 110, "complexity": "medium", "risk": "medium", "justification": "Second view bridge; simpler path than TASK-05"},
"TASK-07": {"task": "Migrate 9 test files + tests_bdd steps to core.services", "lines": 260, "complexity": "medium", "risk": "medium", "justification": "Import churn across 9 files; BDD feature may need rewrite if engine-only"},
"TASK-08": {"task": "Delete pydantic state machine + engine + orchestrator", "lines": 1100, "complexity": "low", "risk": "medium", "justification": "Pure deletion of dead code (1100 lines) after TASK-05/06/07; exceeds 400-line guidance but low risk; requires PM sign-off"},
"TASK-09": {"task": "Delete FastAPI router + CLI + offer float handler", "lines": 400, "complexity": "low", "risk": "medium", "justification": "Deletion of api/cli; offer math port decision resolves LIMIT-21; requires PM sign-off"},
"TASK-10": {"task": "Migrate or delete prei/pipeline/tests + remaining handlers/sources", "lines": 2100, "complexity": "low", "risk": "medium", "justification": "Final prei package removal (2100 lines, mostly tests/sources); exceeds 400-line guidance but is deletion; requires PM sign-off"},
"TASK-11": {"task": "Remove deps from requirements + docs update", "lines": 120, "complexity": "low", "risk": "low", "justification": "requirements.txt edit + docs; pydantic retention depends on tests/acceptance"}
},
"totals": {
"tasks": 11,
"estimated_lines_changed": 4790,
"estimated_new_code": 550,
"estimated_deleted_code": 4240
},
"critical_path": ["TASK-02", "TASK-04", "TASK-05", "TASK-08", "TASK-10", "TASK-11"],
"effort_units": "lines changed (deletions dominate; new code is small)"
}
Loading
Loading