Skip to content

Retry the Bookeo write-back on its own schedule, not the reply checker's - #39

Merged
DorwardTech merged 2 commits into
claude/zone3-darwin-internal-tool-YQKKNfrom
claude/bookeo-writeback-retry
Aug 3, 2026
Merged

Retry the Bookeo write-back on its own schedule, not the reply checker's#39
DorwardTech merged 2 commits into
claude/zone3-darwin-internal-tool-YQKKNfrom
claude/bookeo-writeback-retry

Conversation

@DorwardTech

Copy link
Copy Markdown
Owner

Robert reported 23 lines not on customer files. The dashboard was describing them as "retried hourly". Both halves of that were mine.

Why nothing retried

The retry ran at the end of CheckSmsReplies. That job is scheduled only when crm.reply_checker_enabled is true — and it ships false on purpose, so a deploy can't double up with the Cowork Routine that's still live.

So on a normal install the retry never ran once. The backlog could only grow, and nothing anywhere said so.

// CrmServiceProvider — before
if ((bool) $this->setting($settings, 'crm.reply_checker_enabled')) {
    $schedule->job(new CheckSmsReplies)  // ← the only thing that retried Bookeo

RetryBookeoLog now carries it, gated on crm.bookeo_write_back_enabled alone. Hourly, with no between() window: unlike a reply notification there's nobody to wake, and a customer file that catches up at 3am beats one that waits for morning.

Safe on its own schedule — every row it touches is marked when the write lands and skipped forever after (bookeo_logged_at, mirrored_at), it sends no SMS, and it charges no credits. The worst a spurious run can do is ask Bookeo a question it has already answered.

The dashboard card was worse than silent

"retried hourly" is a claim, and it was printed unconditionally. Whenever write-back is switched off, or Bookeo has no credentials, the number cannot move — and those are exactly the states that produce a backlog somebody notices. The caption sent you looking for a fault in Bookeo when the answer was a setting in this app.

State Caption now
backlog, write-back off write-back is off in Settings
backlog, no Bookeo credentials Bookeo credentials are missing
backlog, both fine retried hourly
no backlog every message is on its customer file

BookeoSmsLog::enabled() is setting && $bookeo->isConfigured(), so those first two are genuinely different faults with different fixes — worth separating rather than collapsing into "off".

--dry-run had the same gap

It reported a count and nothing about whether anything was trying to write it, which is the first question you have when you're staring at a backlog. It now names which of the three states you're in, and points at crm:bookeo-check for the credentials case.

What this does not explain

If the caption turns out to say "retried hourly" — write-back on, credentials present — then Bookeo is refusing the writes, and this PR only makes that visible rather than fixing it. crm:bookeo-check reports whether the key works and whether it's allowed to write customer files, which is the likelier culprit after a key rotation: the customers-write permission is a separate grant.

Tests

  • RetryBookeoLog is scheduled with the reply checker off — the exact bug
  • it disappears when crm.bookeo_write_back_enabled is off
  • it disappears when the module is disabled
  • hourly, onOneServer, withoutOverlapping
  • one dashboard test per caption

The dashboard tests needed a helper: BookeoClient captures its credentials when the singleton is built, so setting config afterwards does nothing until the container forgets the instances that captured them. The existing backlog test was passing only because the test environment has no Bookeo credentials at all — which, with this change, is now a different caption. That's the test catching the new branch, and it's been updated to configure credentials explicitly.

vendor/ can't be installed in this environment (codeload.github.com is blocked by the proxy), so CI is the verification.


Generated by Claude Code

claude added 2 commits August 3, 2026 00:42
23 lines sitting unwritten on a live install, and the dashboard describing
them as "retried hourly". Both halves of that were mine.

The retry ran at the end of CheckSmsReplies. That job is scheduled only when
`crm.reply_checker_enabled` is true, and it ships FALSE on purpose — enabling
it before the equivalent Cowork Routine is disabled would handle every reply
twice. So on a normal install the retry never ran once. The backlog could
only grow, and nothing anywhere said so.

RetryBookeoLog now carries it, gated on `crm.bookeo_write_back_enabled`
alone, hourly, with no between() window: unlike a reply notification there is
nobody to wake, and a customer file that catches up at 3am beats one that
waits for morning. Safe on its own schedule — every row it touches is marked
when the write lands and skipped forever after, it sends no SMS, and it
charges no credits.

## The dashboard was worse than silent

"retried hourly" is a claim, and it was printed unconditionally. Whenever
write-back is switched off, or Bookeo has no credentials, the number cannot
move — and those are exactly the states that produce a backlog someone
notices. The caption sent you looking for a fault in Bookeo when the answer
was a setting in this app.

The card now names the cause: "write-back is off in Settings", "Bookeo
credentials are missing", or "retried hourly" when it really is. Three
states, three captions, one test each.

`crm:bookeo-log-backfill --dry-run` had the same gap — it reported a count
and nothing about whether anything was trying to write it, which is the first
question you have when looking at a backlog. It now says which of the three
you are in, and points at `crm:bookeo-check` for the credentials case.

Guide and README updated: the retry no longer depends on the reply checker,
and the guide gains a troubleshooting entry keyed to the caption on the card,
since that is what somebody will be looking at when they need it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014E51bA27LnFMK7v4YigZY1
The new dashboard fixture was called unmirroredSend(), which
BookeoLogBackfillTest already declares. PHP has one global function
namespace and Pest includes every test file into it, so the second
declaration is a fatal — the whole run died in under a second, before a
single test executed.

Renamed to dashboardUnmirroredSend(). Reusing the existing one instead
would have coupled the two files by collection order, which tests/Pest.php
already warns against.

Added a scan so this cannot come back quietly. It is static rather than a
runtime check for two reasons: the fatal names only the second file, so the
pair is not obvious from the output, and which file loads second depends on
collection order — a collision can hide locally and only fail in CI. The
scan fails one readable test naming both files, in the same order every
time. Verified it catches a planted duplicate, not merely that it returns
empty.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014E51bA27LnFMK7v4YigZY1
@DorwardTech
DorwardTech marked this pull request as ready for review August 3, 2026 00:47
@DorwardTech
DorwardTech merged commit c94e38c into claude/zone3-darwin-internal-tool-YQKKN Aug 3, 2026
2 checks passed
@DorwardTech
DorwardTech deleted the claude/bookeo-writeback-retry branch August 3, 2026 00:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants