|
1 | 1 | # Changelog |
2 | 2 |
|
| 3 | +## 1.6.13 - 2026-05-07 |
| 4 | + |
| 5 | +**Audit hotfix.** Five findings from the post-1.6.12 cold-pass review, |
| 6 | +all on the standalone runtime. CLI variant (`tdpilot-dpsk4`) is |
| 7 | +untouched at the source level; this release rebuilds its .tox solely |
| 8 | +to refresh `API_VERSION` baked into the binary. |
| 9 | + |
| 10 | +### [P1] Reset no longer races against an in-flight worker |
| 11 | + |
| 12 | +`Agent.reset()` used to clear `_stop_flag` unconditionally. If a |
| 13 | +worker thread was still running a turn, the freshly-cleared flag let |
| 14 | +it keep going on a now-empty history — appending stale tool_result |
| 15 | +blocks and potentially making a fresh API call against the cleared |
| 16 | +session. |
| 17 | + |
| 18 | +Post-fix: |
| 19 | + - `Agent.reset()` clears `messages` only. Stop flag stays set. |
| 20 | + - New `Agent.clear_stop()` lifts cancellation explicitly — only |
| 21 | + safe to call after the previous worker has been joined. |
| 22 | + - `AgentRuntime.reset()` reorders: signal stop → cancel pending |
| 23 | + cook calls → join the worker (2s grace) → THEN mutate state → |
| 24 | + finally `clear_stop()`. |
| 25 | + |
| 26 | +### [P1] Compaction no longer orphans tool_result blocks |
| 27 | + |
| 28 | +The compactor's slice point could land inside a tool chain — the |
| 29 | +retained slice would start with a user `tool_result` block whose |
| 30 | +matching assistant `tool_use` was archived. Anthropic-format APIs |
| 31 | +reject that with `messages.0: tool_result block without matching |
| 32 | +tool_use`, so long sessions could 400 exactly when compaction was |
| 33 | +supposed to save them. |
| 34 | + |
| 35 | +Post-fix: `compact()` advances the cut forward past every leading |
| 36 | +`tool_result` so the retained slice starts on a clean boundary. The |
| 37 | +retained slice may end up smaller than `keep_recent` — by design; |
| 38 | +an unsendable history is worse than a slightly smaller one. New |
| 39 | +helper `_starts_with_tool_result(message)` makes the predicate |
| 40 | +testable. |
| 41 | + |
| 42 | +### [P2] Stop pulse no longer leaves worker blocked |
| 43 | + |
| 44 | +`AgentRuntime.stop()` used to set the agent stop flag and push idle. |
| 45 | +But if the worker was blocked inside `CookThreadDispatcher.__call__` |
| 46 | +waiting for a pump, it wouldn't see the flag until the next API call |
| 47 | +(or the 60s timeout). The UI reported idle while `start_turn()` |
| 48 | +still refused new work because the old thread was alive. |
| 49 | + |
| 50 | +Post-fix: `stop()` cancels pending cook calls (waking any blocked |
| 51 | +worker immediately) AND waits up to 2s for the worker to actually |
| 52 | +exit before pushing idle. |
| 53 | + |
| 54 | +### [P2] `tool_batch` sub-calls feed into the severity ledger |
| 55 | + |
| 56 | +The validation-hint system (Phase 1.3) tracked `_turn_tool_calls` |
| 57 | +based on the top-level tool name the agent invoked. When the agent |
| 58 | +called `tool_batch`, the tracker only saw `tool_batch` (severity=low) |
| 59 | +— sub-calls like `td_create_node` or `td_exec_python` hidden inside |
| 60 | +the batch escaped the high-severity hint system entirely. |
| 61 | + |
| 62 | +Post-fix: `_record_tool_call` now peeks inside `tool_batch` results |
| 63 | +and feeds each successful sub-call's name into the ledger. Failed |
| 64 | +sub-calls are skipped (mirrors the top-level "errors don't count" |
| 65 | +rule). A batched `td_create_node` without a follow-up validator now |
| 66 | +fires the same `EV_HINT` a non-batched call would. |
| 67 | + |
| 68 | +### [P3] README title bumped to 1.6.13 |
| 69 | + |
| 70 | +The 1.6.12 release left the H1 in `README.md` reading |
| 71 | +`# TDPilot — DeepSeek v4 · v1.6.11` — `check_versions.py` doesn't |
| 72 | +match that pattern, so it slipped past the lockstep enforcer. |
| 73 | + |
| 74 | +### Tests |
| 75 | + |
| 76 | +9 new regression tests covering reset/stop/compaction/severity: |
| 77 | + - `test_agent_reset_does_not_clear_stop_flag` |
| 78 | + - `test_runtime_reset_joins_worker_before_clearing_history` |
| 79 | + - `test_runtime_stop_cancels_pending_dispatcher_calls` |
| 80 | + - `test_record_tool_call_flattens_tool_batch_subcalls` |
| 81 | + - `test_validation_hint_fires_for_batched_high_severity` |
| 82 | + - `test_compact_returns_synthetic_plus_smaller_recent_when_boundary_repaired` |
| 83 | + - `test_compact_advances_past_multiple_tool_results` |
| 84 | + - `test_compact_handles_pathological_all_tool_results` |
| 85 | + - `test_starts_with_tool_result_helper` |
| 86 | + |
| 87 | +Pytest 1132 passing (up from 1122). Lints + format + version drift + |
| 88 | +sync_counts + personal-path checks all clean. |
| 89 | + |
| 90 | +--- |
| 91 | + |
3 | 92 | ## 1.6.12 - 2026-05-07 |
4 | 93 |
|
5 | 94 | **Standalone runtime overhaul.** The "agent with a big prompt → small runtime |
|
0 commit comments