Repository navigation
fix(task-orphan-check): age from local_time only when it is a real header, never a body line [AgentActivity] - #6028
Conversation
…ader classify_task read local_time from the lenient parse, so for a writer that never stamps it a local_time: line in the user's body became the age and a fresh task was archived unanswered at startup. local_time now comes from the strict pre-task: headers only; otherwise the age falls back to timestamp as before. Also corrects the wording on who stamps local_time and notes that status-ack's deadline stays on the sender's timestamp on purpose.
sonichi
left a comment
There was a problem hiding this comment.
Approving at 1eae439. This fixes the hole I missed in #5929: classify_task used the lenient parse, so a body local_time: line could become the age for any task whose writer never stamps the header. Now local_time comes only from the strict pre-task: headers (ltp.parse_task_headers), and task_queued_at takes it as a separate argument, so the lenient headers can't feed it. Both new tests cover the case: a body line in a legacy task, and a real header beating a body copy. tests/task-orphan-check-classify.test.py passes locally (68/68). CI was still running when I reviewed. The wording now matches the code, including the status_ack_policy.intake_at split.
(agent-assisted, Blue for Chi's seat)
keweichen
left a comment
There was a problem hiding this comment.
Changes requested at 1eae439d — the code fix is correct, but this startup-path PR is not yet approvable.
The parser-provenance blocker from #5929 is fixed. I verified the exact head (68/68 classifier tests, 81/81 status-ack tests, 11/11 local-time writer tests, review scanner and src-map checks clean). The parent negative control at d55138c fails exactly the forged-body case: ('orphan', 'local_time', 216740400) instead of ('fresh', 'timestamp', 12). At HEAD a body-only local_time: falls back to the immutable timestamp, while a real pre-task: header still wins. I found no further code blocker.
Remaining blocker: attach the completed real post-restart witness described in the PR body (named lane; app quit; message held by the broker for >5 minutes; relaunch; that message is answered and is not archived/reported as recovered). The body currently says this is only being scheduled, and no witness is attached. Because this classifier runs on /startup and can archive owner tasks, REVIEW.md lesson 15 makes that end-to-end restarted-service round trip a review-time gate. The worst case without it is a fresh broker-held owner message being archived unanswered despite the unit proof.
Please re-request review after the witness is posted and CI is green.
Coverage Gate✅ Diff coverage PASSES the 95% bar. Whole-tree (informational): 94%. Diff CoverageDiff: origin/main...HEAD, staged and unstaged changes
Summary
|
|
Live post-restart witness for #6028 (run by Mark's coordinator agent on Mark's Mac, local k3d rig) Engine:
a. Engine after relaunch:
Restored afterwards: engine back at |
keweichen
left a comment
There was a problem hiding this comment.
Approved at 1eae439d — ready to merge.
The sole blocker from my prior review is resolved by the posted live witness. It exercised the stated restarted path: real app quit, a named-lane mention held at the broker for 426 seconds, relaunch, one answer, archival only after the REPLIED marker, and no orphan recovery message. The witness timestamps independently reconcile to a 03:28:50Z local intake and a 16-second classifier age; without that strict local_time: header, the sender timestamp would be old enough to trigger the failure mode.
I also verified the public witness commit c8a3a2ef4 uses byte-identical blobs to this PR head for all four changed non-changelog files, including the runtime classifier. Combined with the exact-head 68/68 classifier suite, the parent negative control, 81/81 status-ack tests, 11/11 writer tests, clean review scan, and fully green CI + CLA, this mitigates the worst case: archiving a fresh broker-held owner task unanswered. No remaining blocker or nit.
Follow-up to #5929, which is merged. Fixes the post-merge blocker from @keweichen's review (independently confirmed by @liususan091219), plus @sonichi's wording nits. Based on
main(d55138c).The bug on main
classify_taskparses withparse_task_headers_lenient, and #5929 madelocal_timethe first age source. That parser's own contract (src/local_task_protocol.py) says that when a writer legitimately lacks a key, a body line can supply it. So for a task from a writer that never stampslocal_time:(older writers, other task shapes), alocal_time:line in the user's body becomes the age. A fresh task then reads as an orphan and is archived unanswered at startup.The fix
local_timeis now read from the strict pre-task:headers only (ltp.parse_task_headers). Every current writer stamps it abovetask:: the AG2 Space bridge, event_consumer, and the Slack, Discord, Telegram and task-bridge writers.local_time:header the age falls back totimestamp:, exactly as before fix(task-orphan-check): age a task from when it entered this inbox, not when it was sent [AgentActivity] #5929.task_queued_attakes the strict value as a separate argument, so the lenient headers can no longer feed it.Wording (sonichi's nits):
SKILL.mdno longer say "every writer stamps its own write time". They now say the local writer stamps it at intake: task-bridge.ts builds it from the timestamp it has just taken, andbuild_requeued_taskkeeps the original's, so a requeue does not make a task look fresh.status_ack_policy.intake_at,SKILL.mdand the docstring now say that status-ack's deadline deliberately stays on the sender'stimestamp:, because it measures how long the sender has waited.Evidence
python3 tests/task-orphan-check-classify.test.py, with the new tests, at the parentmain(d55138c):At HEAD:
New tests:
test_a_local_time_line_in_a_legacy_body_is_not_the_age(keweichen's repro shape): a 12 s old task whose writer stamps nolocal_time:, withlocal_time: 2019-10-30T00:00:00+00:00 UTCin the body. It is fresh, aged fromtimestamp.test_a_real_header_wins_over_a_body_copy: the header abovetask:is used, not a body copy.tests/status-ack-policy.test.pypasses.ruff,scripts/review-checks.shandgen-src-map --checkare clean.Live
The post-restart witness keweichen asked for (named lane, app quit, a message held at the broker for more than 5 min, relaunch, the message answered and not archived) is being scheduled on the rig. It will be pasted here when run. The fix is read-side only, in the startup classifier.