Slice 43 - Scheduled Sync Retry Policy
Scope#
Scheduled sync should have an explicit unattended policy without adding a local queue, hosted worker, or new daemon.
Local automation still launches foreground codealmanac sync. The scheduled
command now supplies:
- stable claim owner:
codealmanac.automation.sync - pending timeout:
24h - failed-attempt budget:
3
Shape#
AutomationService
-> ScheduledJob(program_arguments=(..., "sync", "--claim-owner", ...))
-> CLI dispatch
-> RunSyncRequest(claim_owner=..., max_failed_attempts=...)
-> SyncWorkflow
-> SyncLedgerEntry.failed_attemptsSyncLedgerEntry.failed_attempts is durable. It increments when an Ingest run
fails or when sync reconciles a linked failed pending run. Successful absorb
resets it to zero.
When a failed entry reaches max_failed_attempts, sync returns
sync-retry-budget-exhausted as needs-attention instead of retrying forever.
Tests#
- automation install includes stable sync owner, pending timeout, and failed-attempt budget in scheduled argv
- failed sync ingest records
failed_attempts = 1 - exhausted failed entries report
sync-retry-budget-exhausted - focused sync, automation, and CLI tests cover the command path
Cosmic Python Note#
Chapter 11's async messaging section shaped this slice: scheduled sync is an external command source. The adapter should translate that source into explicit command data before workflow code runs. The workflow still owns the durable state transition.