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.
- Connect the key. Expect one read-only
GET /properties?pagination[limit]=1probe; the displayed count is the account total visible to the key. No booking intake starts. - 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.
- 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.
- Drain. Every feed request must carry
filter[property_id]=<test id>. Healthlast_failuremust 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. - Trigger recovery on worker start/deploy. Expect only filtered
/booking_revisions, no/bookingslist, andlast_failure=false. Initial history recovery has no checkpoint and can page the test property’s full history (five revisions per page). - 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-levelproperty_id, documentedpayload.property_id, and a filtered active-mappings fallback when neither is present. Never retain a real delivery body in evidence. - 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.
- 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.
- 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.
- 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.
Messages
Section titled “Messages”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.
- 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.comidentities only. Activation withoutacknowledge_cost: truemust 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 andGET /applications/installedlists for the property. Compare the installed list before and after. Record identifier-only evidence: never keep keys, guest bodies or raw upstream deliveries. - 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 auditfilter_violation. With another system’s installation on the property (simulator only), activation must answer 409messages.installation_foreignand change nothing. - 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
sentoruncertain, never silently retryable. Reconcile by exact Channex ID; a similar text is only a hint. Dismiss is audited and cannot resend. - 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}/messageswith 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. TestPOST /attachments,GET /live_feedandGET /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 callsPOST /live_feed/{id}/resolve; hold it across a stop and verify that the stop returns 503messages.replies_in_flightuntil settlement, then succeeds on an operator retry. Measure how long Channex takes to answer an install and a send. Separately test the thread attachment formPOST /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. - 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
failedand audited, never resent. Repeat with a held feed response and a held upload: late reads are discarded, cursors and health unchanged. - 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 503messages.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 409messages.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 answerschannex.unlink_pendinguntil the install has settled; with a failing compensating uninstall the attempt staysinstalledand 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 answerschannex.unlink_pending(the attempt ispreparing), and the activation installs nothing, removes its webhook and answersmessages.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 answersmessages.activation_incomplete, nothing is installed and the attempt ispreparing; 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, aninstalledattempt 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 (apreparingattempt 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 exactinstalledattempt 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 503channex.property_busywithRetry-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 503messages.activation_incompletewith the current ETag, neverchannex.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. - 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_flightuntil the send ended (refused, so it reaches nobody) or two minutes passed by PostgreSQL’s clock (then it isuncertain, 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. - 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 (409messages.install_attempt_changed), twice in a row, concurrently from two sessions, and withoutmessages.configureor, on a shared account, withoutchannex.manage_account_modeto 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. - 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 answerschannex.unlink_pendingand 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. - 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.retiredfor send, attach, retry and no-reply-needed; mark-read and dismiss stay local. No request to the retired property may occur. - 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/seqhave no gaps. The view shows the newest 1,000; older messages remain stored. - 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.
- Stops from
stoppedand stale stops (simulator). Deactivate, then unlink; a 403, then unlink; unlink, relink without activating, unlink again: each answers 200,pending_unlinksis 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. - 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
contractmigration 0025.