feat(captain): queue document crawl jobs

This commit is contained in:
2026-06-05 19:44:10 +08:00
parent 2923aae26c
commit 89cdb2ad57
6 changed files with 485 additions and 11 deletions
+16 -10
View File
@@ -16,10 +16,10 @@ Build GoChat as a Go backend that can directly reuse the frontend from `referenc
## Current Baseline
- Current tracking checkpoint: 2026-06-05 after `d756473 feat(webhook): queue incoming messages`, with this documentation checkpoint prepared as `docs: land parity execution tracker`.
- Latest implementation checkpoint: `d756473 feat(webhook): queue incoming messages`.
- Current tracking checkpoint: 2026-06-05 after `2923aae docs: land parity execution tracker`, with this implementation checkpoint prepared as `feat(captain): queue document crawl jobs`.
- Latest implementation checkpoint: this checkpoint, prepared as `feat(captain): queue document crawl jobs`.
- Latest documentation-only checkpoint: this checkpoint, prepared as `docs: land parity execution tracker`; this document is now the active follow-up plan and supersedes `.hermes/plans/*`.
- Worktree status at this implementation checkpoint: B11.1a aligns Captain assistant CRUD/tools/inbox bindings; B11.1b aligns Captain scenarios and custom tools; B11.1c aligns Captain documents, assistant responses, bulk actions, and custom-tool test payloads; B11.2 aligns Copilot thread/message create/list/get/delete payloads, account/user scoping, and no-LLM fallback persistence; B11.3a aligns Captain preferences show/update payloads and account-level model/feature storage; B11.3b aligns Captain playground request/response payloads, account scoping, v2 history handling, and no-LLM fallback; B11.3c adds the fakeable Captain document sync backend gate with disabled, failed, and fake-success states; B11.3d aligns Captain task request/response payloads, no-provider disabled states, follow-up context, suggestion persistence, and Copilot message tool-call key validation; B11.3e aligns Captain stream DTOs/disabled SSE fallbacks and Copilot push-event payload shapes; B12.1 adds the reusable GoChat server/seed entrypoint plus a Meilisearch-first reused Chatwoot frontend smoke harness and report; B12.2a adds API smoke assertions for auth/profile, inbox, conversation/messages, contact/company, widget config/message, and public CSAT; B12.2b adds a zero-dependency Chrome DevTools browser smoke that loads the reused Chatwoot login and dashboard entrypoints through Vite and checks browser auth/dashboard API requests; B12.3a adds enterprise API smoke assertions for SLA reports/download, CSAT reports/download, automation/macros, audit/custom roles, capacity, Captain, and Copilot; B12.3b adds reused-frontend enterprise browser route navigation for SLA, CSAT, automation, macros, audit logs, custom roles, capacity, Captain, and Copilot request coverage; P5.1 adds the PostgreSQL-backed durable `background_jobs` model/migration plus WorkerPool enqueue, schedule, retry/backoff, dead-letter, idempotency, stale-lock recovery, and focused tests; P5.2 wires `channel.Dispatcher` and `dispatch.EventDispatcher` async paths into durable event jobs with worker replay tests; P5.3 queues Meilisearch write-side index/delete jobs for conversations, messages, contacts, companies, and articles while keeping search reads Meilisearch-first; P5.4 queues automation webhook and email transcript side effects as durable jobs while preserving fakeable delivery boundaries; P5.5 queues Chatwoot-style macro execute fan-out through durable `automation:macro_execution` jobs; P5.6 queues resolve-triggered CSAT survey sends and WhatsApp/Twilio CSAT template creation through durable jobs; P5.7 queues Chatwoot enterprise SLA account scans and applied-SLA evaluation jobs through the durable worker; P5.8 queues Chatwoot-style contact export artifact generation through durable `contact:export` jobs; P5.9 queues normalized provider inbound message persistence/dispatch through durable `webhook:incoming_message_persist` jobs; P5.10 queues Chatwoot `SendReplyJob`-style outbound message delivery through durable `message:send_reply` jobs and provider delivery-status/read-receipt updates through durable webhook status jobs; P5.11 queues Captain document sync requests through durable `captain:document_sync` jobs; P5.12 queues scheduled item fan-out, one-off campaigns, snoozed conversation reopening, account auto-resolution, widget/public message status updates, and account conversation bulk actions through durable jobs. Next active implementation slice is remaining P5.11 Captain/Copilot jobs, followed by P5.13 analytics aggregation.
- Worktree status at this implementation checkpoint: B11.1a aligns Captain assistant CRUD/tools/inbox bindings; B11.1b aligns Captain scenarios and custom tools; B11.1c aligns Captain documents, assistant responses, bulk actions, and custom-tool test payloads; B11.2 aligns Copilot thread/message create/list/get/delete payloads, account/user scoping, and no-LLM fallback persistence; B11.3a aligns Captain preferences show/update payloads and account-level model/feature storage; B11.3b aligns Captain playground request/response payloads, account scoping, v2 history handling, and no-LLM fallback; B11.3c adds the fakeable Captain document sync backend gate with disabled, failed, and fake-success states; B11.3d aligns Captain task request/response payloads, no-provider disabled states, follow-up context, suggestion persistence, and Copilot message tool-call key validation; B11.3e aligns Captain stream DTOs/disabled SSE fallbacks and Copilot push-event payload shapes; B12.1 adds the reusable GoChat server/seed entrypoint plus a Meilisearch-first reused Chatwoot frontend smoke harness and report; B12.2a adds API smoke assertions for auth/profile, inbox, conversation/messages, contact/company, widget config/message, and public CSAT; B12.2b adds a zero-dependency Chrome DevTools browser smoke that loads the reused Chatwoot login and dashboard entrypoints through Vite and checks browser auth/dashboard API requests; B12.3a adds enterprise API smoke assertions for SLA reports/download, CSAT reports/download, automation/macros, audit/custom roles, capacity, Captain, and Copilot; B12.3b adds reused-frontend enterprise browser route navigation for SLA, CSAT, automation, macros, audit logs, custom roles, capacity, Captain, and Copilot request coverage; P5.1 adds the PostgreSQL-backed durable `background_jobs` model/migration plus WorkerPool enqueue, schedule, retry/backoff, dead-letter, idempotency, stale-lock recovery, and focused tests; P5.2 wires `channel.Dispatcher` and `dispatch.EventDispatcher` async paths into durable event jobs with worker replay tests; P5.3 queues Meilisearch write-side index/delete jobs for conversations, messages, contacts, companies, and articles while keeping search reads Meilisearch-first; P5.4 queues automation webhook and email transcript side effects as durable jobs while preserving fakeable delivery boundaries; P5.5 queues Chatwoot-style macro execute fan-out through durable `automation:macro_execution` jobs; P5.6 queues resolve-triggered CSAT survey sends and WhatsApp/Twilio CSAT template creation through durable jobs; P5.7 queues Chatwoot enterprise SLA account scans and applied-SLA evaluation jobs through the durable worker; P5.8 queues Chatwoot-style contact export artifact generation through durable `contact:export` jobs; P5.9 queues normalized provider inbound message persistence/dispatch through durable `webhook:incoming_message_persist` jobs; P5.10 queues Chatwoot `SendReplyJob`-style outbound message delivery through durable `message:send_reply` jobs and provider delivery-status/read-receipt updates through durable webhook status jobs; P5.11 queues Captain document sync, crawl/parser, and schedule-sync work through durable jobs; P5.12 queues scheduled item fan-out, one-off campaigns, snoozed conversation reopening, account auto-resolution, widget/public message status updates, and account conversation bulk actions through durable jobs. Next active implementation slice is remaining P5.11 response/embedding/Copilot jobs, followed by P5.13 analytics aggregation.
- `go test ./...` passes.
- Route dump succeeds with `TOTAL: 832` after adding the Chatwoot-compatible Twilio delivery-status route plus the legacy namespaced alias.
- Route parity artifacts now exist under `docs/parity/` and are generated by `cmd/route_parity`.
@@ -88,7 +88,7 @@ This table is the shortest authoritative handoff view. If an older lower section
| Priority | Workstream | Current state | Next checkpoint | Commit close rule |
| --- | --- | --- | --- | --- |
| 1 | P5.11 Captain/Copilot jobs | Captain document sync is queued; crawl/response/embedding/Copilot response jobs remain open. | Add fakeable durable jobs for remaining Captain/Copilot async work and disabled-provider states. | Focused Captain/Copilot worker tests plus full `go test ./...`. |
| 1 | P5.11 Captain/Copilot jobs | Captain document sync plus crawl/parser/schedule jobs are queued; response/embedding/Copilot response jobs remain open. | Add fakeable durable jobs for remaining Captain/Copilot async work and disabled-provider states. | Focused Captain/Copilot worker tests plus full `go test ./...`. |
| 2 | P5.13 reports/analytics | Frontend smoke harness exists; `analytics_service` still has placeholder aggregation paths. | Replace frontend-visible report placeholders with real scheduled/cached aggregations. | Report fixtures verify values, cache/freshness behavior, and no hidden placeholder JSON. |
| 3 | Phase 2/3 drift | Tracked route parity is 0 missing for the current critical set; serializer fixtures remain partial. | Expand route/serializer fixtures when smoke or reference inspection exposes drift. | Regenerate parity artifacts and add endpoint-family fixture tests. |
| 4 | Phase 6 placeholder audit | Widget/public/webhook critical placeholders are burned down; account/contact/conversation/message/inbox audit remains broad. | Run a fresh placeholder audit and assign every frontend-reachable stub to a tracked owner. | `rg` audit result is recorded and no reused-frontend blocker is ownerless. |
@@ -100,7 +100,7 @@ These rows are the executable development plan from this point forward. A checkp
| ID | Owner files | Reference files | Work to land | Exit gate |
| --- | --- | --- | --- | --- |
| P5.11a Captain document crawl/schedule | `internal/service/captain_document_service.go`, `internal/service/captain_document_worker.go`, `internal/app/bootstrap.go` | `reference/chatwoot/enterprise/app/jobs/captain/documents/crawl_job.rb`, `schedule_syncs_job.rb`, `perform_sync_job.rb`, Firecrawl/simple parser jobs | Add durable schedule/crawl producers and handlers with fakeable crawl/parser boundaries. Keep missing provider config as `sync_disabled`/retryable failure state, not placeholder success. | Focused Captain document worker tests prove enqueue, replay, retry/dead-letter, account scope, and disabled/failure states. |
| P5.11a Captain document crawl/schedule | `internal/service/captain_document_service.go`, `internal/service/captain_document_worker.go`, `internal/app/bootstrap.go` | `reference/chatwoot/enterprise/app/jobs/captain/documents/crawl_job.rb`, `schedule_syncs_job.rb`, `perform_sync_job.rb`, Firecrawl/simple parser jobs | Durable schedule/crawl producers and handlers with fakeable crawl/parser boundaries. Missing provider config is a failed `crawl_disabled` state, not placeholder success. | Review by `feat(captain): queue document crawl jobs`; focused worker tests prove enqueue, replay, account scope, idempotent scheduler, and disabled/failure states. |
| P5.11b Captain response/embedding fan-out | Captain document/assistant-response services and repositories, Meilisearch/embedding boundaries | `response_builder_job.rb`, `enterprise/app/jobs/captain/llm/update_embedding_job.rb`, FAQ generator/embedding services | Queue FAQ response generation after successful document content changes, reset unedited responses, create/update assistant responses, and fan out embedding update work behind fakeable LLM gates. | Tests cover response reset/create, embedding-disabled state, fake success, idempotent replay, and no external network in default tests. |
| P5.11c Copilot and conversation response jobs | Copilot thread/message services, Captain task services, event/realtime payload helpers | `enterprise/app/jobs/captain/copilot/response_job.rb`, `conversation/response_builder_job.rb`, Copilot chat service | Queue assistant replies after Copilot user messages and Captain conversation triggers. Persist assistant messages/tool-call JSON and emit existing push payloads from worker replay. | Copilot worker tests cover no-provider disabled reply, fake provider success/failure, user/account scope, and restart-safe persistence. |
| P5.13 analytics aggregation | `internal/service/analytics_service.go`, report handlers/services, worker bootstrap | Chatwoot report controllers/services used by dashboard analytics, CSAT/SLA reporting views | Replace frontend-visible placeholder report values with real scheduled or cached aggregations. Define freshness/idempotency rules for expensive rollups. | Report fixtures prove values are derived from persisted conversations/messages/CSAT/SLA rows; `rg` finds no frontend-visible placeholder report JSON. |
@@ -140,6 +140,7 @@ This ledger records the committed parity checkpoints that future slices should b
| Commit | Scope | Verification summary | Follow-up state |
| --- | --- | --- | --- |
| `feat(captain): queue document crawl jobs` | Advances P5.11a with durable Captain document crawl, simple-page parser, and auto-sync scheduler jobs. Document create/crawl requests enqueue `captain:document_crawl`, crawl replay uses a fakeable crawl backend to enqueue normalized `captain:document_page_crawl_parse` jobs, parser replay creates or updates account-scoped document content through a fakeable parser backend, and the `captain:documents_schedule_syncs` root job scans stale synced/failed/syncing documents for accounts with `captain_document_auto_sync` enabled before enqueueing `captain:document_sync` work with daily idempotency. Bootstrap seeds the scheduler after Captain document services are wired. | `go test ./internal/service -run 'CaptainDocumentService\|EnqueueCaptainDocumentScheduleSyncs' -count=1`; `go test ./internal/service ./internal/worker ./internal/app -count=1`; `go test ./...`; `git diff --check`; full verification recorded in the P5.11 section. | P5.11a moves to Review; continue P5.11b response/embedding fan-out, then P5.11c Copilot/conversation response jobs. |
| `docs: land parity execution tracker` | Documentation-only checkpoint requested before continuing implementation. Updates the current baseline to `d756473`, front-loads executable open checkpoint contracts for P5.11 Captain/Copilot jobs, P5.13 analytics aggregation, Phase 2/3 drift, Phase 6 placeholder burn-down, and B12 live smoke, and records commit discipline for future parity slices. | `git diff --check`; documentation-only change. | Start P5.11a Captain document crawl/schedule jobs, then P5.11b response/embedding fan-out and P5.11c Copilot/conversation response jobs. |
| `feat(webhook): queue incoming messages` | Completes P5.9 normalized inbound persistence deferral. `IncomingPersister.PersistIncoming` now validates provider-parsed messages and, when a WorkerPool is configured, enqueues `webhook:incoming_message_persist` instead of creating contacts/conversations/messages inline. Worker replay reloads the inbox, performs the existing Chatwoot-style contact inbox/conversation/message persistence, keeps `source_id` idempotency, and dispatches the same conversation/message events from the durable path. Telegram, LINE, Facebook/Instagram, WhatsApp, TikTok, and Twilio webhook handlers are wired to the WorkerPool while no-worker construction remains synchronous for focused tests. | `go test ./internal/handler/webhook -run 'IncomingPersister.*Incoming\|IncomingPersister.*Status\|StatusJob\|TwilioInboundSMS\|TwilioDeliveryStatus' -count=1`; `go test ./internal/handler/webhook ./internal/channel/whatsapp ./internal/worker ./internal/app -count=1`; `go test ./...`; `git diff --check`; full verification recorded in the P5.9 section. | Move P5.9 to Review; next active slice is remaining P5.11 Captain/Copilot jobs, then P5.13 analytics aggregation. |
| `feat(messages): queue delivery statuses` | Completes P5.10 provider delivery-status depth. `IncomingPersister` can now enqueue direct message status updates as `webhook:message_status_update` jobs and contact-scoped read receipts as `webhook:contact_messages_status_update` jobs on the `low` queue; worker replay reloads the inbox, applies sent/delivered/read/failed transitions without downgrading already-read messages, upserts `delivery_statuses`, dispatches status events, and records provider failure details in `content_attributes.external_error`. Twilio delivery callbacks now return Chatwoot-style `204`, include the exact `/twilio/delivery_status` route plus the legacy `/webhooks/twilio/delivery_status` alias, resolve channels by `MessagingServiceSid` or `AccountSid`/`From`, and enqueue through the same durable path when the WorkerPool is wired. | `go test ./internal/handler/webhook -run 'IncomingPersister.*Status\|StatusJob\|TwilioDeliveryStatus' -count=1`; `go test ./internal/handler/webhook ./internal/service ./internal/worker ./internal/app -count=1`; `go run ./cmd/dump_routes > docs/parity/gochat_routes.txt`; `go run ./cmd/route_parity`; `go test ./...`; `git diff --check`; full verification recorded in the P5.10 section. | P5.10 moved to Review; inbound persistence deferral is completed by `feat(webhook): queue incoming messages`. |
@@ -1637,7 +1638,7 @@ Known hotspots:
- `internal/worker/worker.go` has the committed P5.1 durable core and is already wired to dispatcher, search indexing, automation delivery, macro fan-out, CSAT survey/template sends, SLA scans, contact exports, Captain document sync, and conversation maintenance jobs.
- `internal/service/message_delivery_worker.go` and `internal/handler/webhook/incoming_persister_jobs.go` now cover P5.10 SendReplyJob-style outbound delivery plus provider delivery-status/read-receipt jobs.
- `internal/handler/webhook/*` and provider services now keep verification/parsing in the HTTP path while `IncomingPersister` moves normalized inbound persistence/dispatch behind durable jobs when the WorkerPool is configured.
- `internal/service/captain_*` and `internal/service/copilot_*` have document sync job coverage only; P5.11 still needs crawl/response/embedding/Copilot response jobs.
- `internal/service/captain_*` and `internal/service/copilot_*` now cover Captain document sync, crawl/parser, and schedule-sync jobs; P5.11 still needs response/embedding/Copilot response jobs.
- `internal/service/analytics_service.go` has placeholder analytics/report paths and is the owner for P5.13 aggregation work.
Checklist:
@@ -1645,7 +1646,7 @@ Checklist:
- [x] Add `background_jobs` persistence with job type, payload, queue, status, attempt counters, scheduled/locked timestamps, idempotency key, last error, and completion timestamps.
- [x] Replace `internal/worker/worker.go` placeholder with enqueue, schedule, perform, retry/backoff, dead-letter, and graceful shutdown behavior.
- [x] Map the committed Chatwoot job/listener families to Go worker responsibilities in the tracking table.
- [ ] Finish durable job dispatch for remaining Captain/Copilot jobs, delayed automation actions, and report aggregation.
- [ ] Finish durable job dispatch for remaining Captain response/embedding/Copilot jobs, delayed automation actions, and report aggregation.
- [ ] Add retry and failure logging for the remaining external provider calls.
- [ ] Add tests for the remaining enqueueing, uniqueness/idempotency, delayed execution, retries, worker restart pickup, and fakeable external side effects.
@@ -1668,7 +1669,7 @@ Tracking table:
| P5.8 | Queue contact export artifact generation and completion notification/email. | `account/contacts_export_job.rb` | contact export service and mailer boundary | Export API returns immediately, artifact generation is durable, completion notification/email is fakeable, and download remains stable after restart. | Review by `feat(crm): queue contact exports` |
| P5.9 | Queue inbound provider webhook processing where Chatwoot defers work. | `webhooks/*_events_job.rb`, `webhooks/*_delivery_job.rb` | webhook handlers, provider services | Provider HTTP ack behavior remains Chatwoot-compatible while persistence/dispatch runs through retryable jobs with signature validation preserved. | Review by `feat(webhook): queue incoming messages` |
| P5.10 | Queue outbound message delivery and delivery-status updates. | `send_reply_job.rb`, provider delivery/status jobs | message send/channel services, delivery status handler | Outgoing message creation and provider delivery are separated; retries update message/delivery status exactly once. | Review by `feat(messages): queue send replies` and `feat(messages): queue delivery statuses` |
| P5.11 | Queue Captain document sync, crawl, response building, embeddings, and Copilot responses. | Captain document/crawl/response/embedding/Copilot jobs | `internal/service/captain_document_service.go`, Captain/Copilot services | Existing fakeable disabled/failure gates run under durable jobs; document statuses and Copilot message persistence survive worker restart. | Doing: Captain document sync Review by `feat(captain): queue document syncs`; crawl/response/embedding/Copilot response jobs Todo |
| P5.11 | Queue Captain document sync, crawl, response building, embeddings, and Copilot responses. | Captain document/crawl/response/embedding/Copilot jobs | `internal/service/captain_document_service.go`, Captain/Copilot services | Existing fakeable disabled/failure gates run under durable jobs; document statuses and Copilot message persistence survive worker restart. | Doing: document sync Review by `feat(captain): queue document syncs`; crawl/schedule Review by `feat(captain): queue document crawl jobs`; response/embedding/Copilot response jobs Todo |
| P5.12 | Queue conversation maintenance jobs. | `trigger_scheduled_items_job.rb`, `campaigns/trigger_oneoff_campaign_job.rb`, `conversations/resolution_job.rb`, `reopen_snoozed_conversations_job.rb`, `update_message_status_job.rb`, `bulk_actions_job.rb` | conversation service/handlers | Auto-resolution, snooze reopen, status updates, and bulk actions are scheduled/retryable with idempotent tests. | Review by `feat(conversations): queue maintenance jobs`, `feat(conversations): queue message status updates`, and `feat(conversations): queue bulk actions` |
| P5.13 | Replace placeholder analytics/report builders that need background aggregation. | reporting jobs/services and report controllers | `internal/service/analytics_service.go`, reporting services | Frontend-visible reports no longer use placeholder values; any expensive aggregation is scheduled or cached with freshness rules. | Todo |
@@ -1845,14 +1846,18 @@ P5.11 current checkpoint:
- `captain:document_sync` now mirrors Chatwoot enterprise `Captain::Documents::PerformSyncJob` on the `low` queue. `POST /captain/documents/:id/sync` marks the account-scoped document as syncing and enqueues durable replay when a WorkerPool is configured.
- Worker replay unmarshals the persisted account/document IDs and calls `SyncDocumentByAccount`, reusing the B11.3c fakeable sync backend boundary for disabled provider config, backend failures, explicit backend error codes, successful content/title/fingerprint updates, and account scoping.
- Missing documents or malformed payloads fail the job so retry/backoff/dead-letter state stays observable in `background_jobs`, matching the Chatwoot background-job failure surface instead of silently swallowing bad work.
- `captain:document_crawl` now mirrors the simple crawl fan-out portion of Chatwoot `Captain::Documents::CrawlJob` on the `low` queue. Document create/crawl requests enqueue durable crawl work when a WorkerPool is configured, and crawl replay uses a fakeable backend to produce normalized parser jobs for page links plus the original document URL.
- `captain:document_page_crawl_parse` now mirrors `Captain::Tools::SimplePageCrawlParserJob` for the local simple-crawl path. Worker replay validates assistant/account scope, creates or updates the matching document by assistant/link, stores title/content/fingerprint, marks sync as `synced`, and exposes parser-disabled or content-empty failures without hitting the network in default tests.
- `captain:documents_schedule_syncs` now mirrors the reference auto-sync scheduler shape on `scheduled_jobs`. Bootstrap seeds the scheduler, scheduler jobs use daily idempotency, scan stale synced/failed/syncing completed documents for accounts with `captain_document_auto_sync` enabled, and enqueue `captain:document_sync` work on the `purgable` queue for retryable execution.
- No-worker construction keeps the previous mark-syncing fallback for focused tests and local paths that do not start the durable worker.
- Bootstrap registers Captain document jobs on the shared WorkerPool so production sync requests are replayable after process restart.
- Remaining P5.11 work: Captain crawl jobs, response-building jobs, embedding update fan-out, and Copilot response jobs.
- Bootstrap registers Captain document jobs on the shared WorkerPool so production sync/crawl/schedule requests are replayable after process restart.
- Remaining P5.11 work: response-building jobs, embedding update fan-out, and Copilot response jobs.
P5.11 verification:
```bash
env GOCACHE=/tmp/gochat-gocache GOMODCACHE=/tmp/gochat-gomodcache go test ./internal/service -run 'CaptainDocumentService' -count=1
env GOCACHE=/tmp/gochat-gocache GOMODCACHE=/tmp/gochat-gomodcache go test ./internal/service -run 'CaptainDocumentService\|EnqueueCaptainDocumentScheduleSyncs' -count=1
env GOCACHE=/tmp/gochat-gocache GOMODCACHE=/tmp/gochat-gomodcache go test ./internal/handler/api/v1 -run 'CaptainDocument\|CaptainResource' -count=1
env GOCACHE=/tmp/gochat-gocache GOMODCACHE=/tmp/gochat-gomodcache go test ./internal/service ./internal/handler/api/v1 ./internal/worker ./internal/app -count=1
env TMPDIR=/home/rogee/Projects/gochat/.tmp/test-tmp GOCACHE=/tmp/gochat-gocache GOMODCACHE=/tmp/gochat-gomodcache go test ./...
@@ -1985,6 +1990,7 @@ Verification milestone gates:
## Progress Log
- 2026-06-05: P5.11a Captain document crawl/schedule checkpoint prepared as `feat(captain): queue document crawl jobs`; document create/crawl requests now enqueue `captain:document_crawl`, crawl replay fans out normalized `captain:document_page_crawl_parse` parser jobs through fakeable crawl/parser boundaries, parser replay creates or updates account-scoped documents with synced content/fingerprints, and `captain:documents_schedule_syncs` scans stale completed documents for `captain_document_auto_sync` accounts to enqueue `captain:document_sync` jobs with daily idempotency. Focused Captain document worker tests, service/worker/app package tests, full `go test ./...`, and `git diff --check` passed. Remaining P5.11 follow-up is response/embedding fan-out and Copilot/conversation response jobs.
- 2026-06-05: Parity execution tracker checkpoint prepared as `docs: land parity execution tracker`; the plan now records `d756473 feat(webhook): queue incoming messages` as the current implementation baseline, adds executable contracts for P5.11a/P5.11b/P5.11c Captain/Copilot jobs, P5.13 analytics aggregation, Phase 2/3 drift audit, Phase 6 placeholder burn-down, and B12 live smoke, and makes commit/update discipline explicit for future checkpoints. Documentation-only checkpoint; `git diff --check` passed.
- 2026-06-05: P5.9 inbound webhook deferral checkpoint prepared as `feat(webhook): queue incoming messages`; normalized provider inbound messages now enqueue `webhook:incoming_message_persist` when WorkerPool is configured, while worker replay creates contact inboxes, conversations, messages, and dispatches incoming events from the durable path with source-ID idempotency. Telegram, LINE, Facebook/Instagram, WhatsApp, TikTok, and Twilio persisters are wired to the WorkerPool. Focused webhook/worker tests passed. Next slice is remaining P5.11 Captain/Copilot jobs.
- 2026-06-05: P5.10 provider delivery-status checkpoint prepared as `feat(messages): queue delivery statuses`; provider direct status callbacks now enqueue `webhook:message_status_update`, contact-scoped read receipts enqueue `webhook:contact_messages_status_update`, worker replay upserts delivery status rows, records failed provider `external_error`, preserves monotonic sent/delivered/read transitions, and Twilio status callbacks now support the exact Chatwoot `/twilio/delivery_status` route with `204 No Content`. Focused webhook tests, route generation, full `go test ./...`, and `git diff --check` passed; inbound persistence deferral is completed by the next P5.9 checkpoint.