Skip to content
Open
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
6 changes: 3 additions & 3 deletions desloppify/app/commands/plan/triage/confirmations/organize.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@
)


def _require_enriched_clusters(plan: dict) -> bool:
def _require_enriched_clusters(plan: dict, state: dict | None = None) -> bool:
from ..stages.helpers import unenriched_clusters # noqa: PLC0415

gaps = unenriched_clusters(plan)
gaps = unenriched_clusters(plan, state)
if not gaps:
return True
print(colorize(f"\n Cannot confirm: {len(gaps)} cluster(s) still need enrichment.", "red"))
Expand Down Expand Up @@ -158,7 +158,7 @@ def confirm_organize(
organize_clusters = [
name for name in plan.get("clusters", {}) if not plan["clusters"][name].get("auto")
]
if not _require_enriched_clusters(plan):
if not _require_enriched_clusters(plan, state):
return
if not _require_clustered_review_issues(plan, state):
return
Expand Down
2 changes: 1 addition & 1 deletion desloppify/app/commands/plan/triage/stages/organize.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def _validate_organize_submission(
manual_clusters = _manual_clusters_or_error(plan, open_review_ids=open_review_ids)
if manual_clusters is None:
return None
if not _clusters_enriched_or_error(plan):
if not _clusters_enriched_or_error(plan, state):
return None
if not _unclustered_review_issues_or_error(plan, state):
return None
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ def _manual_clusters_or_error(
return None


def _clusters_enriched_or_error(plan: dict) -> bool:
gaps = unenriched_clusters(plan)
def _clusters_enriched_or_error(plan: dict, state: dict | None = None) -> bool:
gaps = unenriched_clusters(plan, state)
if not gaps:
return True
print(colorize(f" Cannot organize: {len(gaps)} cluster(s) need enrichment.", "red"))
Expand Down
77 changes: 77 additions & 0 deletions desloppify/tests/commands/plan/test_triage_split_modules_direct.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import desloppify.app.commands.plan.triage.runner.orchestrator_codex_pipeline_execution as orchestrator_pipeline_execution_mod
import desloppify.app.commands.plan.triage.runner.orchestrator_codex_sense as orchestrator_sense_mod
import desloppify.app.commands.plan.triage.runner.orchestrator_common as orchestrator_common_mod
import desloppify.app.commands.plan.triage.stages.organize as organize_stage_mod
import desloppify.app.commands.plan.triage.validation.completion_policy as completion_policy_mod
import desloppify.app.commands.plan.triage.validation.completion_stages as completion_stages_mod
import desloppify.app.commands.plan.triage.validation.enrich_checks as enrich_checks_mod
Expand Down Expand Up @@ -268,6 +269,82 @@ def test_confirmation_modules_stage_presence_guards(capsys) -> None:
assert "Cannot confirm" in out


def test_validate_organize_submission_passes_state_to_enrichment_gate(monkeypatch) -> None:
import desloppify.app.commands.plan.triage.stages.evidence_parsing as evidence_parsing_mod

captured: dict[str, object] = {}
state = {"issues": {"review::closed-only": {"status": "closed", "detector": "review"}}}

monkeypatch.setattr(organize_stage_mod, "open_review_ids_from_state", lambda _state: set())
monkeypatch.setattr(organize_stage_mod, "auto_confirm_reflect_for_organize", lambda **_kwargs: True)
monkeypatch.setattr(organize_stage_mod, "_manual_clusters_or_error", lambda _plan, open_review_ids=None: ["manual"])

def _capture_enriched(plan, actual_state):
captured["plan"] = plan
captured["state"] = actual_state
return True

monkeypatch.setattr(organize_stage_mod, "_clusters_enriched_or_error", _capture_enriched)
monkeypatch.setattr(organize_stage_mod, "_unclustered_review_issues_or_error", lambda _plan, _state: True)
monkeypatch.setattr(organize_stage_mod, "_validate_organize_against_ledger_or_error", lambda **_kwargs: True)
monkeypatch.setattr(organize_stage_mod, "validate_backlog_promotions_executed", lambda **_kwargs: [])
monkeypatch.setattr(organize_stage_mod, "_enforce_cluster_activity_for_organize", lambda **_kwargs: True)
monkeypatch.setattr(organize_stage_mod, "_organize_report_or_error", lambda report: report)
monkeypatch.setattr(evidence_parsing_mod, "validate_report_references_clusters", lambda _report, _clusters: [])

services = SimpleNamespace(
collect_triage_input=lambda _plan, _state: {},
detect_recurring_patterns=lambda *_args, **_kwargs: [],
save_plan=lambda _plan: None,
)

result = organize_stage_mod._validate_organize_submission(
args=argparse.Namespace(),
plan={"clusters": {}},
state=state,
stages={"observe": {}, "reflect": {}},
report="x" * 120,
attestation=None,
is_reuse=False,
services=services,
)

assert result == (["manual"], "x" * 120)
assert captured["state"] is state


def test_confirm_organize_passes_state_to_enrichment_gate(monkeypatch) -> None:
captured: dict[str, object] = {}
state = {"issues": {"review::closed-only": {"status": "closed", "detector": "review"}}}

monkeypatch.setattr(confirmations_organize_mod, "ensure_stage_is_confirmable", lambda _stages, stage: True)
monkeypatch.setattr(confirmations_organize_mod, "show_plan_summary", lambda _plan, _state: None)
monkeypatch.setattr(confirmations_organize_mod, "_print_reflect_activity_summary", lambda _plan, _stages: None)
monkeypatch.setattr(confirmations_organize_mod, "count_log_activity_since", lambda _plan, _ts: {})

def _capture_enriched(plan, actual_state):
captured["plan"] = plan
captured["state"] = actual_state
return False

monkeypatch.setattr(confirmations_organize_mod, "_require_enriched_clusters", _capture_enriched)
monkeypatch.setattr(confirmations_organize_mod, "_require_clustered_review_issues", lambda _plan, _state: True)

services = SimpleNamespace(
command_runtime=lambda _args: SimpleNamespace(state=state),
)

confirmations_organize_mod.confirm_organize(
argparse.Namespace(),
{"clusters": {}},
{"reflect": {"timestamp": ""}},
None,
services=services,
)

assert captured["state"] is state


def test_confirmation_pipeline_structures_enrich_level_results(monkeypatch) -> None:
import desloppify.app.commands.plan.triage.validation.enrich_quality as enrich_quality_mod

Expand Down