51 lines
2.2 KiB
Markdown
51 lines
2.2 KiB
Markdown
# Issue #5 Phase 2b Round 3 review (`8d7e010`)
|
|
|
|
- **Reviewer**: `reviewer-creator-grok-01`
|
|
- **Job**: `7e7eea07`
|
|
- **HEAD**: `8d7e010` (`fix(issue-5): record an accepted intent, not a refused one`)
|
|
- **Prior Grok residual**: `0d502d33` item 1 — `seen_intents` recorded before the seq check
|
|
- **Tests this turn**: `pytest tests/test_issue5_phase2b_autocomplete.py tests/test_issue5_phase2a_loop.py` → **156 passed**. Phase 2b file: **65 collected**. Collect-only **732**. `git diff --check 9a651cc..HEAD` clean.
|
|
|
|
The live callback was re-read and the stale-first probe from `0d502d33` was re-run against this tree.
|
|
|
|
---
|
|
|
|
## Adjudication
|
|
|
|
[ADJUDICATION: SUSTAINED]
|
|
|
|
`job_subscriber.py:143-179` now splits the two operations:
|
|
|
|
1. **Lookup** of `identity in seen_intents` still runs *before* the seq guard, so a replay with a fresh wire seq is dropped.
|
|
2. **`seen_intents.add`** runs *after* `seq > last_seq` and after `last_seq` is advanced. A refused packet does not mark its intent as accepted.
|
|
|
|
Malformed `notification_intent` (non-object, or unhashable field) is dropped inside defensive parsing with a warning; `TypeError` does not escape the MQTT callback.
|
|
|
|
Required regression `test_r4b_a_stale_packet_does_not_burn_the_intent_for_its_own_retry`: `last_seq=10`, seq=9 refused, same intent at seq=11 accepted, `qsize()==1`, a further replay stays at 1.
|
|
|
|
**Reproduced this turn** (same probe that failed on `9a651cc`):
|
|
|
|
```
|
|
stale seq=9 last=10 -> qsize=0 seen=set() last=10
|
|
retry seq=11 same intent -> qsize=1
|
|
replay seq=12 -> qsize=1
|
|
unhashable: raised=False qsize=0 last=0
|
|
```
|
|
|
|
Also covered: refused replay does not raise `last_seq` (`test_r4b_a_duplicate_intent_does_not_advance_the_sequence_floor`); end-to-end two `notifier.flush` attempts with distinct wire seqs land once on the real callback (`test_r4b_a_real_retry_is_deduplicated_by_the_real_consumer`).
|
|
|
|
---
|
|
|
|
## Residuals (unchanged, not this patch)
|
|
|
|
1. No production caller of `evaluate` / `recover` (Phase 3; §2-1).
|
|
2. `started` does not mint `dispatch_token`.
|
|
3. Bookkeeping may write any `pending_notification` value, not only `None`.
|
|
4. `pick_pending` split-lock.
|
|
|
|
No `[ESCALATE: PLANNER]`. This is the local order fix the residual asked for.
|
|
|
|
---
|
|
|
|
[VERDICT: PASS]
|