[831988ba] Fix PRECONDITION_OWNERSHIP rejection kind in lifecycle spec + update affected test (#256) (#257) (#258)

* [831988ba] fix(lifecycle): add rejection_kind to Precondition, PRECONDITION_OWNERSHIP uses not_authorized

Add rejection_kind: RejectionKind = 'tracing_gap' field to the Precondition
frozen dataclass. PRECONDITION_OWNERSHIP now carries rejection_kind='not_authorized'
so ownership failures surface as authorization issues rather than tracing gaps.

Update _check_intent_preconditions to dispatch Decision.reject(kind='not_authorized')
when the first failing precondition has rejection_kind='not_authorized' — for all
other rejection_kinds the existing Decision.tracing_gap path applies.

Update test_can_invoke_intent_open_pr_rejects_non_owner to assert not_authorized
instead of tracing_gap (90 parity tests in test_lifecycle_consumer_parity.py
now agree: choreographer and spec both return not_authorized for owned=False).

All 4871 foundation tests pass, 3264 unit tests pass, ruff/mypy green.

* [831988ba] docs(architecture): document preconditions and rejection kinds in lifecycle spec

Add comprehensive guide explaining how Precondition rejection_kind field works in
the lifecycle spec. Documents the distinction between tracing_gap (missing artifact)
and not_authorized (identity/role boundary) rejections, includes the dispatch logic
in _check_intent_preconditions, and explains agent-visible impact of the change.

This context is essential for agents to understand why PRECONDITION_OWNERSHIP failures
now return not_authorized instead of tracing_gap, and when to use each rejection_kind
for new preconditions.

---------

Co-authored-by: Backend Developer 1 <be-dev-1@agents.roboco.dev>
Co-authored-by: Backend Documenter <be-doc@agents.roboco.dev>
This commit is contained in:
Renzo F
2026-06-25 05:02:49 +02:00
committed by GitHub
co-authored by Backend Developer 1 Backend Documenter
parent 88ad03c8cb
commit cfef0f3019
3 changed files with 177 additions and 4 deletions
+2 -3
View File
@@ -623,7 +623,7 @@ def test_can_invoke_intent_open_pr_passes_when_owner_with_commits() -> None:
def test_can_invoke_intent_open_pr_rejects_non_owner() -> None:
"""Non-owner trying open_pr → tracing_gap with owns_task missing."""
"""Non-owner trying open_pr → not_authorized (PRECONDITION_OWNERSHIP)."""
owner_id = uuid4()
intruder_id = uuid4()
task = _stub_task(
@@ -639,8 +639,7 @@ def test_can_invoke_intent_open_pr_rejects_non_owner() -> None:
context=spec.Context(actor_id=intruder_id),
)
assert d.allowed is False
assert d.rejection_kind == "tracing_gap"
assert "owns_task" in d.missing
assert d.rejection_kind == "not_authorized"
# ---------------------------------------------------------------------------