afk: wire the T3 adapter to the REAL orchestration contract + fix priority
The T3 dispatch adapter was written against a guessed wire shape that the test
fake accepted but the live t3-afk server 400s — so the previously-green suite did
NOT mean the loop was actually wired to T3. Reverse-engineered the real contract
from the v0.0.27 binary, verified it live against t3-afk (including multi-turn),
and rewrote the adapter to match:
- dispatch sends BARE commands keyed by `type` (not a `command` string), with
client-minted threadId/commandId/messageId + createdAt; the server replies
{sequence}, so dispatch returns the id it generated (never one parsed back).
- a thread lives in a project (workspaceRoot = the repo checkout the agent runs
in), so dispatch ensures the repo's project (snapshot -> project.create iff
absent) before thread.create + thread.turn.start.
- add send_turn() for follow-up turns on an existing thread — multi-turn context
retention is verified live (turn 2 recalled turn 1).
- watcher reads thread liveness from latestTurn.state (completed->idle,
running/in_progress/pending->running, errored->error), not a non-existent
top-level `status` field.
Guard against recurrence: the test fake now REJECTS any command lacking a `type`
discriminator (the original bug fails loudly), plus an opt-in live smoke test
(tests/test_afk_t3_live.py) so "green" can mean "wired to T3".
Also align dispatch_policy to lower-priority-value-first (P0 before P1), matching
tracker conventions and Issue.priority's own docstring — it had deliberately
diverged to higher-first. Loop still ships DISABLED (kill switch on, empty
allowlist). 416 tests pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
2ef0db9a96
commit
e34640cc47
8 changed files with 555 additions and 272 deletions
|
|
@ -176,14 +176,15 @@ def test_custom_in_progress_label_drives_the_lock(fake_tracker, fake_t3, make_is
|
|||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# One dispatch per repo per tick (the policy's one-agent-per-repo invariant,
|
||||
# observed through the poller): highest-priority eligible issue wins the slot.
|
||||
# observed through the poller): the most urgent (lowest-value) eligible issue
|
||||
# wins the slot.
|
||||
# --------------------------------------------------------------------------- #
|
||||
def test_one_dispatch_per_repo_per_tick(fake_tracker, fake_t3, make_issue):
|
||||
fake_tracker.seed(
|
||||
"infra",
|
||||
[
|
||||
make_issue(number=1, repo="infra", priority=1),
|
||||
make_issue(number=2, repo="infra", priority=9), # highest priority
|
||||
make_issue(number=1, repo="infra", priority=1), # most urgent (lowest value)
|
||||
make_issue(number=2, repo="infra", priority=9),
|
||||
make_issue(number=3, repo="infra", priority=5),
|
||||
],
|
||||
)
|
||||
|
|
@ -191,8 +192,8 @@ def test_one_dispatch_per_repo_per_tick(fake_tracker, fake_t3, make_issue):
|
|||
|
||||
_poller(fake_tracker, fake_t3).run_once(config)
|
||||
|
||||
assert _dispatched_pairs(fake_t3) == {("infra", 2)}
|
||||
assert _added_in_progress(fake_tracker) == {("infra", 2)}
|
||||
assert _dispatched_pairs(fake_t3) == {("infra", 1)}
|
||||
assert _added_in_progress(fake_tracker) == {("infra", 1)}
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue