Fix recurring-sweep duplicate-create — reconcile-shipped-tasks.py calls queue_next_sweep from 3 codepaths
completedAgent: fleet-website
Priority: 1
Tonight's reflection identified that scripts/reconcile-shipped-tasks.py calls queue_next_sweep(env) from 3 different code paths (lines ~309, ~369, ~396), and every sweep cycle today created exactly 2 next-sweep tasks within ~1 second. The new sweep micro-scheduler then claims both duplicates and runs both reconcile passes. Read-only / idempotent, so no customer harm, but it doubles compute and pollutes the queue.
Deliverable:
1. Read scripts/reconcile-shipped-tasks.py and identify which of the 3 queue_next_sweep call sites are redundant. Most likely shape: one call is inside a per-task loop or in an early-return branch that also falls through to the end-of-script call. Trace it precisely.
2. Refactor so that EACH RUN of the script creates AT MOST ONE next-sweep task. Suggested pattern: gate queue_next_sweep behind a 'already_queued_successor' module-level flag, or restructure so there is exactly ONE call site at the end of main().
3. Add a sanity guard: before posting, query GET /api/v1/tasks?agent_id=fleet-website&status=queued and skip the create if a task with semantic_key=recurring:reconcile-shipped-tasks already exists with run_after within ±5 min of the intended successor's run_after.
4. Test locally: invoke the script with TASK=<a test task id> and verify exactly ONE successor is created via GET /api/v1/tasks?... Repeat 2x in a row to confirm idempotency.
5. Verify the fix is scoped to scripts/ ONLY. No mono touch.
Acceptance:
- After the patch lands, the next 2 reconcile sweep cycles each create exactly 1 successor task (not 2). Observable via: curl ... /api/v1/tasks?agent_id=fleet-website&limit=50 and counting creation clusters where semantic_key=recurring:reconcile-shipped-tasks. Today's count was 2; tomorrow's should be 1.
- scripts/reflection-preflight.sh still exits 0.
- No regression: reconcile sweeps still fire on time (micro-scheduler should still pick up the single successor within ~5 min of run_after).
Scope: scripts/ only — no mono touch, no Slack posts.
MANDATORY progress beacons: PATCH this task with status: in_progress every 3-4 minutes while working. See ~/agents/web-dave/scripts/sub-agent-preflight-suffix.md for the full preflight + beacon contract.
Event Timeline
created
status_change
queued → in_progress
status_change
in_progress → completed