Skip to content

Shared-account live-test checklist

This checklist is for a separately authorized operator on a dedicated synthetic test property. It records planned live verification; the automated PR tests use only the independent simulator and disposable PostgreSQL. Never switch a company shared account to exclusive or link another customer’s property.

Before the live session, use a disposable workspace to verify that a member limited to one property receives a refusal for candidate discovery, link and unlink, even when their custom role lists both Channex configuration and account-mode permissions. Perform the live steps as an unrestricted administrator.

  1. Connect the key. Expect one read-only GET /properties?pagination[limit]=1 probe; the displayed count is the account total visible to the key. No booking intake starts.
  2. In Channels, choose the local test property and paste the dedicated Channex ID. Read the fetched title and full ID in the confirmation dialog. Cancel once and verify no mapping was saved. Confirm only after comparing both with the dedicated test property. The warning explains that, after room mapping, GuestCraft acknowledges its bookings and another system on the account stops receiving them.
  3. Reload: the link is marked inactive. Webhook registration is disabled until a room type is mapped. Request a drain before mapping a room type. Expect no feed/history/current reads or acknowledgements for this property. Pending test bookings must remain available upstream. Inspect the fetched room types, map at least one, save and reload to verify persistence.
  4. Drain. Every feed request must carry filter[property_id]=<test id>. Health last_failure must be false. New/modified/cancelled test bookings should be applied and acknowledged. If Channex ignores the property filter, stop and unlink; the existing fail-closed alert must be visible. No circuit breaker is implemented.
  5. Trigger recovery on worker start/deploy. Expect only filtered /booking_revisions, no /bookings list, and last_failure=false. Initial history recovery has no checkpoint and can page the test property’s full history (five revisions per page).
  6. Register/check the webhook twice. In Channex, expect exactly one GuestCraft booking callback on the test property, is_global=false, send_data=false. A new test booking must wake intake within seconds. Delivery routing supports top-level property_id, documented payload.property_id, and a filtered active-mappings fallback when neither is present. Never retain a real delivery body in evidence.
  7. If testing ARI, map compatible rate plans and explicitly take over publication. Verify changes reach only the dedicated test property. Independently confirm with the other system’s owner that its unrelated properties still receive bookings.
  8. Open Unlink, verify the property ID and preservation warning, cancel once, then confirm. Reload: no active mapping or publication, and imported reservations and history still exist. The GuestCraft callback must be removed; other consumers’ callbacks must remain. Queued ARI rows are retired, not marked delivered. If cleanup fails, expect an inactive pending-removal warning; retry it before relinking.
  9. Send another synthetic test booking after unlink. Expect no read/ack/application or ARI for that property. Relink via title/ID confirmation: it is inert again until a room type is mapped. Publication requires fresh plan mapping and explicit takeover. Unlink cannot undo acknowledgements or writes transmitted before it committed.
  10. Check the audit entries for mapping save, unlink and webhook removal. Never include keys, secrets, guest/card data or raw upstream bodies in logs or screenshots.

Only after the shared-account steps above pass and the full suite is green. All actual calls target a dedicated synthetic test property authorized by the Channex account owner, with the Messages price for its property type confirmed with that owner. Run every race and fault injection below against the independent simulator first (the automated suites do this; see ADR 0044, amendment of 2026-10-29) and only then repeat what can be repeated live. Never use another client’s property or real guest data.

Before any paid live action. The required CI checks must pass on the head that is tested, including the automated race regressions of ADR 0044. On the built application, walk through confirm and forget from a pending-unlink card, the “Remove installation” action, a pending unlink and its recovery, each with reload, denied access, keyboard use and an accessibility check. Run every fault and held-call case below against the simulator first.

  1. Obtain the account owner’s separate authorization for the exact dedicated property, the Messages price for its property type and the grants used. Keep shared-account mode. Compare the full local and upstream property and room IDs, confirm with the account owner that no other system has installed Messages on the property, and leave every unrelated property and callback unchanged. Use synthetic conversations and example.com identities only. Activation without acknowledge_cost: true must install nothing; with consent, verify the property-scoped Messages webhook exists before the paid installation, and that the stored installation ID is the one Channex’s install answer returned and GET /applications/installed lists for the property. Compare the installed list before and after. Record identifier-only evidence: never keep keys, guest bodies or raw upstream deliveries.
  2. Confirm every feed request has filter[property_id] for the test property. In simulator staging, return a foreign feed, thread, message and request item: no foreign detail read, storage or send; show and audit filter_violation. With another system’s installation on the property (simulator only), activation must answer 409 messages.installation_foreign and change nothing.
  3. Send exactly one synthetic text reply and attachment. Force a local commit failure after upstream acceptance, then a lost response: the guest receives at most one copy; the outbox says sent or uncertain, never silently retryable. Reconcile by exact Channex ID; a similar text is only a hint. Dismiss is audited and cannot resend.
  4. What Channex refuses after the uninstall (live, the property’s own data only). After a deactivation, and again after an unlink, call each endpoint of the guarantee per endpoint (ADR 0044) for one of the property’s own threads and bookings directly with the API key: GET /message_threads/{id}, its messages page, POST /message_threads/{id}/messages, POST /bookings/{id}/messages with an attachment ID and, on a Booking.com thread, POST /message_threads/{id}/no_reply_needed. Record each actual status and its effect on the chat and the booking; the listed thread sends must reach no guest after uninstall. Resolve is measured separately because Live Feed decisions are not protected by the installation. Test POST /attachments, GET /live_feed and GET /live_feed/{id} separately and record their statuses: do not presume that the upload is accepted (the documentation lists a 403 for it; the simulator accepts it). Establish what “no reply needed” does for the guest, with provider evidence or by observing the synthetic guest’s side, before and after the uninstall. GuestCraft calls POST /live_feed/{id}/resolve; hold it across a stop and verify that the stop returns 503 messages.replies_in_flight until settlement, then succeeds on an operator retry. Measure how long Channex takes to answer an install and a send. Separately test the thread attachment form POST /message_threads/{id}/messages {message:{attachment_id}} on an inquiry with no booking; the automated path is simulator-only and the documented booking attachment form does not prove upstream thread support. Record resolve after uninstall, including its finality and guest effect. Such measurements show observed latency only and cannot prove the two-minute bound. Reactivate afterwards.
  5. A stop refuses success during decisions and closes sends (simulator). Hold a text send, an attachment send and a no-reply-needed call after their admission. Unlink, deactivate, or answer 403 to another drain: a stop returns 503 while an admitted decision remains unsettled and requires an operator retry; once it succeeds, GuestCraft’s installation is gone, and the released call is refused, reaching no guest; the reply ends failed and audited, never resent. Repeat with a held feed response and a held upload: late reads are discarded, cursors and health unchanged.
  6. Install attempts (simulator). Let the simulator make the installation and lose its answer: activation answers 409 messages.install_unconfirmed, adopts nothing and uninstalls nothing; confirming it as GuestCraft’s lets activation finish without a second install, and deactivation removes it. Lose the following list as well: activation answers 503 messages.install_pending; within two minutes nothing is listed or installed again, after them the attempt becomes unconfirmed. Install another system’s application between GuestCraft’s list and its install: GuestCraft’s install is refused, activation answers 409 messages.installation_foreign, and nothing of the other system is adopted or removed, also when GuestCraft’s answer is lost too (then unconfirmed, and leaving it touches nothing). Hold an install across unlink: the unlink answers channex.unlink_pending until the install has settled; with a failing compensating uninstall the attempt stays installed and the unlink retry removes it; with the process lost between install and record, the unlink waits for the operator’s decision. Hold an activation inside its intent transaction while an unlink arrives: the unlink waits for the lock, then answers channex.unlink_pending (the attempt is preparing), and the activation installs nothing, removes its webhook and answers messages.mapping_changed; with the process lost after the webhook, the unlink removes the webhook after two minutes. Let the webhook registration fail and its removal too: activation answers messages.activation_incomplete, nothing is installed and the attempt is preparing; install another system’s application on the property, and after two minutes deactivate: GuestCraft removes its webhook, ends the attempt and offers nothing for confirmation, and the other installation stays. Deactivate generation 1, hold a reactivation’s install (then its webhook registration, then its list after a lost answer) and deactivate again: pending answers 503, an installed attempt is uninstalled and the deactivation succeeds, an unconfirmed one answers 409 until the operator decides, and the held reactivation never becomes active afterwards. Stage a failed uninstall, an ambiguous answer, a failed list and a late install. Kill the process at each of the eight boundaries (intent committed, webhook registered, webhook rollback failed, install sent, install answered, attempt recorded, compensation sent, stop committed), restart it and let the drain run: the state is the one the server’s crash matrix expects (a preparing attempt after a lost intent, webhook or rollback, which a stop after the bound ends by removing the webhook, never offering an installation that another system made meanwhile; pending, then unconfirmed, after a lost answer; the exact installed attempt after a recorded one; the unlink’s visible retry after a lost compensation; a visible pending stop after a lost stop commit). Hold the property’s row lock in another session for more than two seconds and deactivate, unlink, confirm, forget, save a Channex mapping, retry a revision, or repair, map or resync ARI: each answers 503 channex.property_busy with Retry-After: 2, nothing changes, and the same request succeeds once the lock is free. Hold it after an activation’s webhook registration, and after it finished a pending stop: the activation answers 503 messages.activation_incomplete with the current ETag, never channex.property_busy, installs nothing while the lock is held, and the Messages card shows the attempt (preparing) or stop it left after the reload. Every reported success leaves either no installation of GuestCraft or an explicit, audited operator decision to leave one; every failure has a visible, durable retry or reconciliation.
  7. Reactivation and the bound (simulator). Hold a text and an attachment send of generation 1 across each stop and attempt a reactivation before they settle: activation answers 503 messages.replies_in_flight until the send ended (refused, so it reaches nobody) or two minutes passed by PostgreSQL’s clock (then it is uncertain, audited, never resent). Run a second instance whose application clock is minutes ahead or behind: the bound does not move. Then freeze a process beyond two minutes and let the simulator complete an install or a send after the bound: these are the residuals of ADR 0044. Obtain the account owner’s explicit decision on them before relying on the guarantee.
  8. Operator decisions and ETags (simulator, then live). Confirm and forget from a pending-unlink card; with a stale ETag (412 messages.version_mismatch), with the other property’s installation ID or one that changed (409 messages.install_attempt_changed), twice in a row, concurrently from two sessions, and without messages.configure or, on a shared account, without channex.manage_account_mode to confirm. The ETag must differ for no attempt, an unconfirmed and a confirmed one, and after a relink: read the ETag of a pending unlink, finish the unlink, link the property to another upstream property (and once again to the same one), and the old ETag answers 412 with the current one. Each change is audited once with the actor and the installation ID. Nothing is adopted or uninstalled automatically.
  9. Cleanup failure. Make the uninstall fail (simulator; live only if the account owner accepts a temporary pending state): deactivation answers messages.cleanup_failed, the Messages screen shows the pending stop with Retry, nothing is read or sent, and Retry finishes it. Unlink answers channex.unlink_pending and stays visible in Channels until its retry. A 404 completes cleanup. Only GuestCraft’s installation and webhooks may be removed; another system’s installation and callbacks remain.
  10. Relink first to the same, then to a different dedicated upstream test property; repeat after switching account mode. Cancelled replies stay terminal in either case. Old different-property threads/requests remain history with 409 messages.retired for send, attach, retry and no-reply-needed; mark-read and dismiss stay local. No request to the retired property may occur.
  11. Drain 1,100-message threads in newest-first and oldest-first order through worker restarts. Add 50 messages between pages of the first read and again between drains. Verify every ID appears once, the sync cursor persists until all history is read, and message_count/seq have no gaps. The view shows the newest 1,000; older messages remain stored.
  12. Run two workers against one thread and one queued reply through PgBouncer transaction mode. Verify one upstream send, one stored row per message and gapless sequence/read state. Stage two overlapping thread drains with a failed page: the new sync row survives and the newest message is stored exactly once, in both listing orders.
  13. Stops from stopped and stale stops (simulator). Deactivate, then unlink; a 403, then unlink; unlink, relink without activating, unlink again: each answers 200, pending_unlinks is empty, relink works, and GuestCraft’s webhooks and installation are gone. Hold a first unlink at its uninstall, let a second finish, relink and activate, then resume the first: it answers 412 and leaves the new installation and webhook intact.
  14. Verify webhook wake-up and the five-minute safety tick, then reload the UI. Check the current API revision’s status and problem codes, banner wording, keyboard navigation, History badge announcement, permission denial, invalid drafts and recovery on the built deployment. Exercise request decisions, special offers, inquiry attachments, retention and typed erasure confirmation; decide the synthetic request in the channel’s extranet and verify the final outcome refresh. After the final stop, verify the installed ID is gone, pending cleanup is empty, unrelated integrations are intact, and billing has ended with the account owner. Record the migration revisions and the promotion and roll-forward recovery plan of the contract migration 0025.