feat(gateway): C8 PM-decision gate windowed satisfaction

_check_pm_decision_required now requires the latest journal:decision
within pm_decision_window_seconds (default 300). Older decisions no
longer satisfy the gate. Adds JournalService.latest_decision_at.

Future-tighten (out of scope): per-verb-group consumption tracking
would need persistent state — Choreographer is per-request today.
This commit is contained in:
Renn F
2026-05-12 06:27:33 +02:00
parent 89eacf028e
commit 41ef7f6b4e
38 changed files with 631 additions and 29 deletions
@@ -56,8 +56,7 @@ def test_i_will_plan_rejects_missing_approach() -> None:
assert resp.status_code == _HTTP_UNPROCESSABLE, resp.text
detail = resp.json()
assert any(
"approach" in str(err.get("loc", []))
for err in detail.get("detail", [])
"approach" in str(err.get("loc", [])) for err in detail.get("detail", [])
), detail
@@ -106,9 +105,7 @@ def test_i_will_plan_schema_accepts_rich_plan() -> None:
"Single-cell decomposition for the smoke test: be-pm handles "
"git workflow validation end to end."
),
sub_tasks=[
{"title": "Backend slice", "description": "Branch + edit + PR"}
],
sub_tasks=[{"title": "Backend slice", "description": "Branch + edit + PR"}],
risks=[],
open_questions=[],
)