Skip to content

Commit 692376f

Browse files
committed
test: cover recon note->discovery coercion and audit-phase activation
Regression guard for the dispatch-hub convergence fix. Recon agents post findings as ledger note entries; every audit phase gates on an exact discovery-kind condition, so without coercion the phase graph never leaves recon. Verifies _post_ledger_writes records a recon-phase note as a discovery, leaves notes untouched outside recon, leaves requests untouched in recon, and that the coerced discovery activates the audit-phase condition. Provider-independent.
1 parent 4bb5373 commit 692376f

1 file changed

Lines changed: 98 additions & 0 deletions

File tree

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
"""Recon note->discovery coercion activates the discovery-gated audit phases.
2+
3+
Regression guard for the dispatch-hub convergence fix: recon agents post
4+
findings as ledger ``note`` entries, but every audit phase gates on
5+
``make_discovery_condition("discovery")`` (exact kind equality). Without
6+
coercion the phase graph never advances past recon. ``_post_ledger_writes``
7+
now records a recon-phase ``note`` as a ``discovery`` so the audit phases
8+
can activate; outside recon the kind is left untouched.
9+
10+
Provider-independent -- proves the convergence wiring without a live LLM.
11+
"""
12+
from __future__ import annotations
13+
14+
from types import SimpleNamespace
15+
16+
from aila.platform.agents.turn_runner import AgentTurnRunnerBase
17+
from aila.platform.contracts.reasoning import (
18+
LedgerWrite,
19+
ReasoningCaseState,
20+
ReasoningTurnDecision,
21+
)
22+
from aila.platform.services.ledger import LedgerService, make_discovery_condition
23+
from aila.platform.uow import UnitOfWork
24+
25+
_RECON = ReasoningCaseState(
26+
observables={"_directive.phase_mission": "RECON PHASE. Objective: scope the target."},
27+
)
28+
_AUDIT = ReasoningCaseState(
29+
observables={"_directive.phase_mission": "SOURCE AUDIT PHASE. Objective: audit."},
30+
)
31+
32+
33+
async def test_recon_note_is_coerced_to_discovery(test_db) -> None:
34+
del test_db
35+
inv, branch = "inv-recon-coerce", "b-recon"
36+
me = SimpleNamespace(investigation_id=inv, branch_id=branch)
37+
decision = ReasoningTurnDecision(
38+
reasoning="scoped surfaces",
39+
ledger_writes=[LedgerWrite(kind="note", payload={"surface": "cli main()"})],
40+
)
41+
async with UnitOfWork() as uow:
42+
await AgentTurnRunnerBase._post_ledger_writes(me, decision, 1, uow.session, _RECON)
43+
await uow.session.commit()
44+
rows = await LedgerService().read_general(inv)
45+
assert len(rows) == 1
46+
assert rows[0]["kind"] == "discovery"
47+
48+
49+
async def test_note_outside_recon_is_untouched(test_db) -> None:
50+
del test_db
51+
inv, branch = "inv-audit-note", "b-audit"
52+
me = SimpleNamespace(investigation_id=inv, branch_id=branch)
53+
decision = ReasoningTurnDecision(
54+
reasoning="x",
55+
ledger_writes=[LedgerWrite(kind="note", payload={"n": 1})],
56+
)
57+
async with UnitOfWork() as uow:
58+
await AgentTurnRunnerBase._post_ledger_writes(me, decision, 1, uow.session, _AUDIT)
59+
await uow.session.commit()
60+
rows = await LedgerService().read_general(inv)
61+
assert len(rows) == 1
62+
assert rows[0]["kind"] == "note"
63+
64+
65+
async def test_request_in_recon_is_untouched(test_db) -> None:
66+
del test_db
67+
inv, branch = "inv-recon-req", "b-req"
68+
me = SimpleNamespace(investigation_id=inv, branch_id=branch)
69+
decision = ReasoningTurnDecision(
70+
reasoning="x",
71+
ledger_writes=[LedgerWrite(kind="request", payload={"intent": "replan"})],
72+
)
73+
async with UnitOfWork() as uow:
74+
await AgentTurnRunnerBase._post_ledger_writes(me, decision, 1, uow.session, _RECON)
75+
await uow.session.commit()
76+
rows = await LedgerService().read_general(inv)
77+
assert rows[0]["kind"] == "request"
78+
79+
80+
async def test_coerced_discovery_activates_audit_condition(test_db) -> None:
81+
del test_db
82+
inv, branch = "inv-activate", "b-act"
83+
me = SimpleNamespace(investigation_id=inv, branch_id=branch)
84+
# Recon posts a note; coercion records it as a discovery.
85+
decision = ReasoningTurnDecision(
86+
reasoning="found a surface",
87+
ledger_writes=[LedgerWrite(kind="note", payload={"surface": "parser"})],
88+
)
89+
async with UnitOfWork() as uow:
90+
await AgentTurnRunnerBase._post_ledger_writes(me, decision, 1, uow.session, _RECON)
91+
await uow.session.commit()
92+
# The audit-phase activation condition now fires (before the fix it never did).
93+
condition = make_discovery_condition("discovery")
94+
enabled, reason = await condition(
95+
{"investigation_id": inv, "_dispatch_phase_trust": "advisory"},
96+
)
97+
assert enabled is True
98+
assert "discovery" in reason.lower()

0 commit comments

Comments
 (0)