Project
Changelog
On this page
- 0.4.13 — 2026-10-28
- 0.4.12 — 2026-10-21
- 0.4.11 — 2026-10-20
- 0.4.10 — 2026-10-20
- 0.4.9 — 2026-10-20
- 0.4.8 — 2026-10-19
- 0.4.7 — 2026-10-18
- 0.4.6 — 2026-10-18
- 0.4.5 — 2026-10-18
- 0.4.4 — 2026-10-18
- 0.4.3 — 2026-10-18
- 0.4.2 — 2026-10-17
- 0.4.1 — 2026-10-13
- 0.4.0 — 2026-10-12
- 0.3.0 — 2026-10-10
- 0.2.2
- 0.2.1 — 2026-09-27
- 0.2.0 — 2026-09-25
- 2026-10-28 — Contract structure and retained judgements
- 2026-10-28 — Native reply-attachment qualification
What changed in each HappyToHelp release, newest first.
Versions follow Semantic Versioning. Before 1.0.0, a minor version (for example 0.2 to 0.3) may include breaking changes, so when you upgrade, read the notes for every version between yours and the new one. For updating and backing up an installation, see Updates and recovery.
0.4.13 — 2026-10-28
No breaking change.
-
Contract evidence: shared contract generation retains the cleanup format through the legacy command entry point. Coverage and clause maps now follow the current source reference, and carried completion claims are partial where the consolidated public journeys no longer assert every required outcome. Product requirements and existing qualification boundaries are retained.
-
Setup manifest binding: rer-project.json now declares
setup{rer-setup.json, sha256 of that file}, so a Platform install of this release reads the setup manifest at the approved commit; the drift-guard script added with it is removed again and the binding stays. -
App pass (H6 to H20, UI-001): inbox views in the rail, ticket actions in the reply card's "+" start menu, the right panel as the ticket's record and the system UI face in place of Inter (H6/H7/H8/H9/H12/H13/H14); the assigned agent's initial at 13px (H11); condensed inbox rows (H16); daily work in the left menu and configuration under Settings (H18); one shared tooltip on every icon-only control (H19); a one-step local trial in Setup (H20); comfortable, scoped Settings click and focus targets with one focus ring, and reply attachment upload failures shown with recoverable drafts kept (UI-001); the installer theme kept to rer's grammar.
-
Widget: presence-based away: with no teammate online the widget shows the away message, which is not a teammate's reply for automations or outcomes (WIDGET-001, migrations 240 and 241); opening hours from applicable SLA calendars with away replies and the reply estimate kept; proactive widget campaigns with consented attribution, a daily-cap fence and consent-revocation cleanup (migration 243).
-
Workflows, forms and SLAs: request forms and typed answers in routing and SLA policies, On-hold policy choices, signed workflow webhooks executed once, field history and current field permissions; account lookup fields (FORMS-001, migration 259); SLA Slack escalations with explicit destination consent and durable outcomes (migration 257_sla_slack); reviewed Zendesk first-response SLA policies imported as inactive.
-
Customers and identity: operator-reviewed identity links (CUSTOMER-001, migration 242) with "possibly the same customer" links on the customer page and ticket, and kept link and unlink history (migration 252); inherited workspace and inbox names are refused.
-
Mail: Managed conversation mail v1 with route observation (migrations 249 and 250), authentication holds and settled held scheduled replies; mailbox protocol and operator ticket doors, proven form CCs, requester notice batches with preview, rate limits and durable notice commands (migration 255); bounded inbound receipt and API hold lookups (migration 256).
-
Move-in and portability: reviewed Zendesk, Freshdesk and Help Scout configuration as native drafts, preserved imported ticket lifecycle (246), signed survey response surfaces and widget survey cycles (244, 245), causal AI handoff receipts (247), optional customer recovery (248), complete native restore and hosted archive export coverage; explicitly supplied Freshdesk attachment bytes (MOVE-IN-002, migration 257_move_in_attachment_bytes); the move-in journeys folded within the test budget.
-
Knowledge: internal knowledge reads limited to each role's selected articles (migration 251), with the compatibility and selection-revocation repair.
-
API and connections: the machine support request API with credential entities, shared admission, quotas and erasure inventory (API-002, migrations 253 and 254); the read-only HubSpot customer context API, its owner and admin connection interface and stable HubSpot panels (CRM-001, migration 257_hubspot_context), with operator first-message sends recovered through the queue; Teams escalation handoffs from a ticket (ESCALATION-001, partial, migration 258_teams_escalations).
-
Procedures, agents, feedback and reports: immutable procedure versions with isolated synthetic simulation (PROCEDURE-001, migration 258_procedure_versions), saved procedure comparison and revision lineage and more readable saved procedures; redacted conversation execution traces joined to their resolution cycles (AGENT-002); human-confirmed incident suggestions (CONV-003); conservative native AI containment reports (REPORTS-002); source-linked feedback with signed release updates and a Penny handoff (FEEDBACK-001), and regulated-deployment qualification records (ASSURANCE-001) (migrations 260, 261 and 262).
-
Dependencies: Zod 3.24.2 to 4.6.6 with public validation responses preserved, postal-mime 3.0.0 to 4.0.8, the undici override 7.29.1 to 7.30.1 and Vite 8.2.2 to 8.2.4; react-tooltip and zod-to-json-schema are removed.
-
Tests, CI and documentation: duplicate browser journeys run once with a phone smoke, within the test budget; Verify in eight balanced shards with reusable proven runs, rerun artifacts, 30-minute browser jobs and timer-polled plugin-frame waits; contract re-judgements and text rulings, the API-002 clause, SOURCE-001 status, the no-Node installation guide and AGENTS.md landing and conflict-resolution guidance.
-
Migrations:
240_operator_presence.sql,241_away_reply_not_a_reply.sql,242_customer_identity_links.sql,243_widget_campaigns.sql,244_csat_response_surface.sql,245_widget_survey_cycles.sql,246_imported_ticket_lifecycle.sql,247_ai_handoff_receipts.sql,248_customer_recovery.sql,249_rer_conversation_mail.sql,250_rer_mail_route_observation.sql,251_knowledge_read_selection.sql,252_customer_identity_link_history.sql,253_api_requests.sql,254_api_erasure_inventory.sql,255_outbound_notice_commands.sql,256_inbound_lookup_indexes.sql,257_hubspot_context.sql,257_move_in_attachment_bytes.sql,257_sla_slack.sql,258_procedure_versions.sql,258_teams_escalations.sql,259_account_lookup_fields.sql,260_feedback.sql,261_assurance.sql,262_feedback_penny.sql. Apply once, in this order and by file name, through pinned rer before the updated Worker serves traffic. -
Upgrade: Update from v0.4.12, or any earlier line, to v0.4.13 without resetting. Back up D1, R2, Durable Object state and private settings first. Install frozen dependencies with Node 22.20.0, pnpm 10.12.4 and pinned @runeditrun/rer 0.2.77. Retain private settings, owners, imported support history, permissions, files, erasure fences and migration history; never delete, reorder or edit ledger rows. Run rer deploy --dry-run against the retained installation first. Apply the following twenty-six migrations once, in listed order and by file name, through pinned rer before the updated Worker serves traffic: 240_operator_presence.sql, 241_away_reply_not_a_reply.sql, 242_customer_identity_links.sql, 243_widget_campaigns.sql, 244_csat_response_surface.sql, 245_widget_survey_cycles.sql, 246_imported_ticket_lifecycle.sql, 247_ai_handoff_receipts.sql, 248_customer_recovery.sql, 249_rer_conversation_mail.sql, 250_rer_mail_route_observation.sql, 251_knowledge_read_selection.sql, 252_customer_identity_link_history.sql, 253_api_requests.sql, 254_api_erasure_inventory.sql, 255_outbound_notice_commands.sql, 256_inbound_lookup_indexes.sql, 257_hubspot_context.sql, 257_move_in_attachment_bytes.sql, 257_sla_slack.sql, 258_procedure_versions.sql, 258_teams_escalations.sql, 259_account_lookup_fields.sql, 260_feedback.sql, 261_assurance.sql, 262_feedback_penny.sql. An earlier installation also applies its other missing published migrations by name through pinned rer. Held secrets inherit; the seven Google, Microsoft and IMAP mailbox settings stay optional, and the new Managed email inputs are optional and unused by a native installation, whose MAIL_PROVIDER stays direct. Connection credentials for Slack, Teams, HubSpot and Penny never enter exports; reconnect them after a restore. Escalation connections keep no provider credentials in exports; retain human Send and unconfirmed recovery. The v0.4.12 recovery note for Platform-applied installs still applies. No breaking change.
0.4.12 — 2026-10-21
No breaking change.
- Hono security patch: the Worker runtime dependency Hono moves from 4.13.7 to 4.13.11, which fixes Hono's static path decoding vulnerability.
- H5/H10/H11 app pass: stylesheets only. Selected navigation and the open inbox row show selection with a wash or a complete hairline ring, never a border on one side of a rounded rectangle; the active rail item has an accessible aqua highlight; the in-app Setup page uses up to 1100px; small app text is raised one step.
- AUTOMATION-002/QUEUE-002 proof: tests and documentation only. Journeys prove time-based automations, including the seeded rule that closes solved tickets after four days, and structured queue work; both clauses now read done.
- Platform migration-ledger guard with rer 0.2.77: export and leave backups now work on Platform-applied installs without re-running their database migrations. Incomplete or conflicting migration history (a
rer_migrationsledger that is missing rows, sits beside a second ledger or does not match the migration files) is refused with exit 4 before data changes, and an empty legacyd1_migrationsis never dropped automatically; native installs retain their usual migration path. The installer pins rer 0.2.77, including migration-ledger checks and the narrowed GitHub-reference rule; restore journeys run in their own CI shard. - Migrations: No migrations. v0.4.12 adds no migration file, so a v0.4.11 installation's migration ledger stays unchanged.
- Upgrade: Update from v0.4.11, or any earlier line, to v0.4.12 without resetting. Back up D1, R2, Durable Object state and private settings first. Install frozen dependencies with Node 22.20.0, pnpm 10.12.4 and pinned @runeditrun/rer 0.2.77. Retain private settings, owners, imported support history, permissions, files, erasure fences and migration history; never delete, reorder or edit ledger rows. Run rer deploy --dry-run against the retained installation first. v0.4.12 adds no migration, so a v0.4.11 installation's migration ledger stays unchanged and nothing is applied. An earlier installation applies its missing published migrations once, in order and by file name, through pinned rer before the updated Worker serves traffic. Held secrets inherit and the seven Google, Microsoft and IMAP mailbox settings stay optional. Escalation connections keep no provider credentials in exports; retain human Send and unconfirmed recovery. No breaking change.
- Recovery note (Platform-applied installs): if an export made with v0.4.11 or earlier failed, it may have left an empty
d1_migrationstable beside the completerer_migrationsledger. v0.4.12 refuses that state as multiple migration histories (exit 4) before any write and never drops either table. Do not delete or edit either table by hand. Recovery is a separate, verified operator procedure for that one installation, taken only after a fresh snapshot and with an explicit source scope; this release performs no cleanup. Native installs, whose history isd1_migrationsalone, are unaffected.
0.4.11 — 2026-10-20
No breaking change.
- R9a companies and customer CSV: company records, domains, membership, reversible merge and mapped CSV preview, apply and undo with import-local fences.
- R10a reports, handle timers, problems and incidents: permission-scoped team reports and scheduled CSV, adjustable handle timers with named lead stops, reviewed incident updates and delivery history.
- R12a escalations: encrypted engineering connections, reciprocal issue links, selected attachment grants, idempotent webhook state, approved customer drafts and Slack handoff. Exports keep no provider credentials; human Send stays.
- Native signout and rer 0.2.74: audited POST /auth/signout retires only the current session; the pinned installer retains existing deployment resources and private state.
- H1 homepage hero: one drawing tells both moments, with Pay now clear of the offer card at narrow phone and desktop widths.
- H3 Ink rail app theme: the accepted rail, form and identity styling reaches the installed application.
- Scanner fixture correction: the synthetic Slack escalation token is assembled from parts with identical runtime bytes; every assertion and product behavior is retained.
- TRIAGE-001: asynchronous intent, sentiment and language predictions, operator correction labels and explicitly approved intent routing; other rules act at admission and default placement never overrides a teammate.
- Migrations:
192_companies.sql,193_customer_csv.sql,194_csv_run_fences.sql,195_restore_trigger_boundaries.sql,196_csv_touched_fences.sql,201_report_timers_schedules.sql,202_problem_incidents.sql,203_problem_delivery_history.sql,204_problem_preview_audit.sql,205_handle_timer_lead_stop.sql,220_ticket_triage.sql,230_escalations.sql. Apply by name through pinned rer before the updated Worker serves traffic. - Upgrade: Update from v0.4.10, or any earlier line, to v0.4.11 without resetting. Back up D1, R2, Durable Object state and private settings first. Install frozen dependencies with Node 22.20.0, pnpm 10.12.4 and pinned @runeditrun/rer 0.2.74. Retain private settings, owners, imported support history, permissions, files, erasure fences and migration history; never delete, reorder or edit ledger rows. Run rer deploy --dry-run against the retained installation first. Apply the following twelve migrations once, in listed order and by file name, through pinned rer before the updated Worker serves traffic: 192_companies.sql, 193_customer_csv.sql, 194_csv_run_fences.sql, 195_restore_trigger_boundaries.sql, 196_csv_touched_fences.sql, 201_report_timers_schedules.sql, 202_problem_incidents.sql, 203_problem_delivery_history.sql, 204_problem_preview_audit.sql, 205_handle_timer_lead_stop.sql, 220_ticket_triage.sql, 230_escalations.sql. An earlier installation also applies its other missing published migrations by name through pinned rer. Held secrets inherit and the seven Google, Microsoft and IMAP mailbox settings stay optional. Escalation connections keep no provider credentials in exports; retain human Send and unconfirmed recovery. No breaking change.
0.4.10 — 2026-10-20
- Synthetic fixture credential. Rename the cron-backlog signing token and its matching inbound request to an explicitly synthetic value so RER's hosted source scanner accepts the published archive. The existing test still verifies the same mail, scheduling and backlog behavior.
- Ticket collaboration markup. The follow and live-collaboration area of a conversation is now a labelled group, so its label is valid ARIA in every state, including while the follow controls are still loading. It looks the same.
- Deterministic account-security journey. The emitted-runtime test helper opens a Worker inspector only when a port for it is given, instead of implying one on the next port that might be taken; workerd could then hang without reporting ready. The readiness wait is a named wall-clock bound sized from measured starts. Every assertion of the journey is unchanged.
- Upgrade from 0.4.9. No new migrations. Keep rer 0.2.68, back up and retain private settings and the migration ledger without resetting. The seven mailbox settings remain optional. Production deployment is separate.
0.4.9 — 2026-10-20
- RER queue recipe. Match the JOBS consumer's three retries to the deployment specification and Wrangler so fresh Managed installs and upgrades approve matching resource plans.
- Declaration drift check. The existing installer journey compares all queue-consumer and schedule fields across the recipe, deployment specification and Wrangler's declared settings. CI fails on differences without pinning their values.
- Upgrade from 0.4.8. No new migrations. Keep rer 0.2.68, back up and retain private settings and the migration ledger without resetting. Existing owners, support history and files remain; the seven mailbox settings stay optional. Production deployment is separate.
0.4.8 — 2026-10-19
- Support workflows (R5). Business hours and holiday calendars, first/next response and resolution SLAs, event and time rules, routing, follow-ups, snoozes and scheduled replies. Preview before publishing; existing SLA and default-close previews remain inert.
- One budget for the whole cron invocation. Workflow recovery, operator-mail dispatch and audit work share a single database statement budget within D1's invocation limit.
- Durable bulk work. Bulk assignments and macros deliver teammate notices during the request when its budget permits. Queued work resumes after interruptions; exhausted batches record each ticket's outcome. Cron recovery completes notices within its remaining budget, and interrupted attempts retain visible uncertainty without replay.
- Installer and deployment. Pin rer 0.2.68, including blob-less release reads and safe temporary cleanup (#313), declared mail-provider keys and migration-sized provider budgets (#314), missing-secret dry-run refusal, large-seed publication scanning and portability that skips rer-owned ledgers.
- Upgrade from 0.4.7. Back up D1, R2, Durable Object state and private settings. Apply exactly
150_workflow_journal.sqlthrough156_ticket_batch_jobs.sqlwith the pinned rer before serving traffic. Missing migrations are planned by name and bytes, including below already applied rows, with final readback. Preserve owners, imported history, permissions, files and erasure fences; never reset or edit the ledger. The seven mailbox settings remain optional.
0.4.7 — 2026-10-18
- Optional mailbox setup. Deployments can omit the seven Google, Microsoft and IMAP configuration values. Held secrets keep their existing bindings; every other deployment binding is unchanged. Email settings explains unavailable connections and disables their connect actions until configured.
- Upgrade from 0.4.6. No new migrations. Back up, retain private settings and deploy with pinned rer 0.2.51. Existing owners, support history and files remain. An installation on 0.4.5 still receives exactly 0.4.6's fifteen missing migrations by name; never reset or edit the ledger.
0.4.6 — 2026-10-18
- Macros and private collaboration (R4). Versioned action macros preview changes and editable reply text before Send. Private notes, mentions, followers, collision indicators, reversible merges and partner collaboration retain permissions and private history.
- Notices to proven recipients. Editable received and solved notices, Cc relay and AI replies reach independently proven addresses only. Frozen delivery claims preserve uncertainty without replay; Cc headers alone grant no recipient authority.
- Complete email (R6). Connect Gmail, Microsoft 365 or IMAP; manage aliases and signatures, CC/BCC, threading, operator-created tickets and vendor matching. Refused and unreadable mail goes to Suspended; bounded per-message failures keep healthy intake moving. Receiving proof remains separate from sender and recipient authority.
- Customer portal and request forms (R7b). Configurable request forms create native tickets with typed fields and idempotent submissions. Independently verified customers can use the portal to follow their permitted tickets and reply, with private team history protected.
- Installer qualification. Exact upgrade expectations include participant provenance; historical archive policies deduplicate exclusions so README restore and native portability complete.
- Dropdown carets. Include the shared select-caret styling.
- Upgrade from 0.4.5. Back up and apply
140_macros.sqlthrough146_participant_provenance.sqland160_mailboxes.sqlthrough164_mailbox_message_attempts.sql, plus172_request_forms.sql,173_customer_portal.sqland174_portal_mailbox_requester.sql, through pinned rer 0.2.51 before serving traffic. These fifteen migrations sort below already applied production rows and are planned by name, with bytes and final readback checked. Retain credentials, history, imports, files and private settings; never reset or edit the ledger. Existing participants remain unproven until independently verified. R5 is not included.
0.4.5 — 2026-10-18
- Hosted migration history. Pin
@runeditrun/rer0.2.51. Deployments from gated migration subsets can apply missing migrations that sort below already applied rows. Rer checks applied names and recorded bytes, refuses unknown names, changed bytes and uncertain history, and verifies the final set by name and bytes. - Upgrade from 0.4.4. No new migrations or product changes. Back up and deploy with the pinned rer without resetting or editing migration history. Existing credentials, support history and file bytes remain. Earlier releases receive every migration they lack in filename order before traffic resumes.
- Test harness. Includes main's
5f7c1f3queue-consumer isolation for test runtimes; product behavior is unchanged.
0.4.4 — 2026-10-18
- Replies to Closed tickets. A customer's emailed reply to a Closed ticket is recognized as on an open ticket, including a widget visitor answering through the reply address, and always opens a new ticket for that customer instead of a separate contact or another open ticket of theirs. A teammate's emailed reply to a Closed ticket is refused with a bounce or an email notice, never stored as a customer message.
- Capacity check. The 1,000-conversation import journey asserts live isolate memory after a forced garbage collection, below 64 MiB, instead of an uncollected heap figure that moved with GC timing.
- Upgrade from 0.4.3. No new migrations. Back up, then replace the Worker; existing credentials, support history and file bytes remain.
0.4.3 — 2026-10-18
- Release qualification. Fresh-clone journeys retain the complete local owner entry, invoke the pinned pnpm consistently and compare restore against the exported Durable Object snapshot. Upgrades preserve every original value except the exact documented email-proof and owner-alert migrations. New migrations 124 and 126 bracket the 125 email-proof backfill so a contact erasure interrupted under 0.4.1 cannot rewrite integration history recorded since; the identical erasure guard is restored before traffic.
- Ticket work. Native statuses, priorities, groups, custom fields, saved views and previewed bulk updates retain the existing conversation history and permissions. Closed tickets are final: a customer reply to a Closed ticket, by email or widget, opens a new ticket for the same customer, and required fields are enforced when they change or on the move into Solved or Closed. Migration 191 indexes ticket history by conversation, so new conversations and large imports no longer scan the whole history.
- Documentation. The docs gain the standard Run and Contract pages built by
@runeditrun/rer0.2.45, now the pinned command package. - Recovery. A failing satisfaction-survey dispatch no longer blocks other scheduled recovery work, surveys wait until survey signing is configured, and the help center offers reader sign-in only when it has restricted collections.
- Upgrade from 0.4.2. Back up and apply the migrations listed in RELEASE.json before serving traffic. Existing credentials, support history and file bytes remain.
0.4.2 — 2026-10-17
-
Mailbox confirmation. Owners claimed by email and moved-in teammates without a second factor confirm sensitive actions by a single-use, 15-minute email sign-in link. Requests are limited atomically and audited. Email is also offered beside existing passwords. After mailbox proof, Profile lets an owner replace an unknown password without the old one; deliberately set passwords keep working. Merely requesting email grants no proof.
-
Conversation history export. Reports downloads full workspace JSON with messages, private notes and attachment names. Empty widget drafts no longer inflate Reports or its analytics CSVs.
-
Honest mail status. A reply whose visitor address matches the sender explains why no email was sent.
-
Deployable tag. The install guide covers PATH and names v0.4.2, using rer 0.2.42.
-
Two-factor sign-in. Add an authenticator app or a passkey (security key, Touch ID, Windows Hello) on your profile, with ten single-use recovery codes. Owners can require it by role from Settings → Security; teammates set it up at their next sign-in before they see anything, and sessions without it end. Wrong, reused and spent codes are refused, limited and logged. An owner can reset a teammate's factors, and a locked-out owner recovers with an installation key set through
rer, never by email alone. -
Confirm it's you. Exports, contact erasure, role changes, installing integrations and credentials, and deleting a workspace ask for the second factor (or the password, without one) again after 15 minutes.
-
Collaborator and custom roles. Invite a collaborator who can read conversations, add internal notes and follow them, but never reply to customers. Settings → Roles creates roles that narrow Agent, Collaborator or Admin, for example an agent who cannot publish articles or export data.
-
Security log. Settings → Security log lists sign-ins, two-factor and role changes, imports, exports, erasure, assignments and approvals with who, where, when and the result; export it as CSV or JSON, set retention and place legal holds. Entries cannot be edited.
-
Erasure reaches connected services. Erasing a contact sends every webhook a signed
contact.erasedrequest and shows, per store and provider, what was removed, what was asked and what cannot be recalled. -
Backups carry Durable Object storage.
rer exportrecords every Durable Object's stored records with a schema and digest, andrer importchecks them before restoring. -
Mark source fixtures as synthetic so hosted changes can admit the public source without changing test coverage.
-
Freshdesk Move in. Tickets with every reply and private note, contacts, agents (as authors only), canned responses and attachment names come across from a script on the Move in page. Signed attachment links are never kept.
-
Move in review you can act on. The plan shows right after upload, in plain words: what will import, what needs fixing (file, line, reason) and what stays in your original file. Approve appears only when something can import. A rejected record no longer holds its source ID, so a corrected file imports it; imported records are linked by subject or name.
-
Imported history lands as it was. Solved and closed conversations from Zendesk, Intercom, Help Scout and Freshdesk land closed, and imported messages never count as unread.
-
Pages a newcomer can finish. API tokens, Webhooks, Slack and Local computers explain each value and where it comes from, with copyable commands and a webhook signature check. A published article no longer offers Publish again. A local trial's workspace is no longer named after its checkout folder; Setup asks for your business name instead.
Included since 0.4.1
Added
-
Hosted native owner claim. Rer can claim the configured installation owner once through
/auth/bootstrap, then retire its private token. The claim uses the native account, workspace and session transaction without installing an unknown password; concurrent or repeated claims preserve the existing owner. Local password setup remains available. -
Help Scout Move in. Review and import supported Inbox v2 and Docs v1 API response bodies as native history and knowledge. JSON, JSONL and ZIP groupings are packaging conventions, not Help Scout exports. Saved replies and attachment bytes are omitted; real-account compatibility remains unverified.
-
Deliberate uncertain webhook resend. Owners/admins can inspect the receiver and approve the original delivery ID/body again from Connections → Delivery log. Only 429 retries automatically within the existing four-attempt budget; 5xx, 408, timeouts and redirects remain uncertain. Each approval beyond the budget permits one audited attempt. A resend can duplicate an effect.
-
Guided local-agent fixes. Investigation, explicitly approved Resolve, separate observation and an operator-reviewed reply retain human Send. A Resolve report does not prove the customer system changed. The documented journey uses a scripted provider boundary and disposable target.
-
Provisioned new workspaces. Non-demo workspaces gain a default starter assistant, reply mailbox when configured and the installation sender until their own domain is verified. Explicit creation may send one welcome email; uncertain mail is never replayed. A bounded initial website read keeps private knowledge without publishing articles. Without an AI key, conversations stay with the team.
Fixed
- Re-import keeps native edits. Unchanged source records retain edited native targets while new records can be imported; changed sources or conflicting ancestry remain review conflicts. Category insertion no longer invalidates unrelated articles; deletion updates only affected ancestry.
- Runtime and documentation consistency. Preview declares generated core migrations, documentation edits reach the development watcher, and bounded hydration recovery retains explicit failure reporting.
Changed
- First run and Setup. The one-screen form derives optional names and colours. Setup separates Needs you from What we've set, observes applicable checks automatically with freshness bounds and permits durable owner/admin skips. A skip never counts as confirmation; rejected keys remain Needs you. Empty inboxes show one next action and a link to Setup.
- Workspace appearance and navigation. A neutral light canvas, lighter fields and softer menus accompany the revised inbox and settings navigation. Dark-theme tokens remain.
- Package commands and automatic local setup. Checkout commands pin published
@runeditrun/rer0.2.25. Rer dev v2 enters as the real native owner throughRER_OPEN; local visitor and teammate email is suppressed without storage or external sending. The README path isnpm install -g @runeditrun/rer, clone, thenrer dev: the command provisions pinned tools, installs dependencies and sets up a local origin and private owner password without private answers or external mail/AI credentials. Thev0.4.1tag predates package conversion, so updating requires current source and frozen dependency installation.
Updating from 0.4.1
Back up and apply 120_activation_observations.sql then 121_move_in_categories.sql before starting the updated Worker. Migration 120 adds nullable observation data without backfill; 121 replaces category revision triggers without rewriting existing rows. Never reset to upgrade. See Updates and recovery.
These notes claim no hosted installation, real vendor-account compatibility, paid-provider execution, import capacity or operating-cost qualification. Synthetic fixture boundaries, accessibility HOLD and D1/R2-only backup limits remain; see Acceptance.
0.4.1 — 2026-10-13
Fixed
- Worker memory while applying or undoing a large import. Undoing a 1,000-conversation import could peak above 128 MiB of sampled Worker heap in verification. A reviewed import is now split into children of at most 10 records (was 20), each invocation applies or reverses up to 20 journal rows (was 10), and the D1 request meter counts UTF-8 bytes without copying every bound value. Reviews and imports created by 0.4.0 keep their recorded children and stay resumable and undoable.
- Move in reviews of up to 5,000 records. Preparing a review read the database twice for every child, so the smaller children pushed imports of roughly 2,500 records or more (and every 5,000-record import, in 0.4.0 too) past the Worker's 1,000-query limit. They stayed in "Preparing review" with no error. Authority is now checked once before and once after all child plans are written. A review's decisions and diagnostics, which passed D1's 2 MB row limit for 5,000 Intercom records, are kept as a private object under the import's storage prefix; the import row keeps the summary and the object's hash. Reviews prepared by 0.4.0 are read unchanged. A background step that still runs out of queries records the error on the import, which the page shows with Resume import.
- Delivery build. The delivery workflow allows 90 minutes, enough for the full verification, frees the runner disk space Verify already frees, and uses Node.js 22.20.0 like the rest of the project.
No migration. A 0.4.0 installation merges v0.4.1; a 0.3 installation follows
Upgrading from 0.3.x.
0.4.0 — 2026-10-12
Added
- Move in. Owners and admins import support history (conversations, contacts, tags, saved replies and articles) from supported Zendesk and Intercom exports. Each import shows its plan, rejections and conflicts before you approve it, keeps original source IDs, timestamps and publication state, resumes after a stop and can be undone. Applying or undoing an import sends no mail and starts no model work, assignment or notification.
- Resolution feedback and Reports. A visitor can rate the answer to their resolved conversation with thumbs up or down and an optional comment. Each resolution records how it was reached (AI, assisted, human or unknown). Reports show volume, median and p90 first-response and resolution times, AI resolution and satisfaction for a workspace-calendar range, with a daily series and formula-safe CSV exports. Imported history is excluded.
- Connections. Scoped workspace API tokens (seven scopes, shown once, stored hashed, revocable), thirteen Bearer API operations, four signed webhook events with delivery logs, and Slack delivery. Explicit HTTP 5xx and 429 answers are retried a bounded number of times; timeouts and redirects are reported as uncertain and never replayed.
- The rer local path.
pnpm exec rer install,setupanddevreplacescripts/install.mjs,scripts/setup.mjsandscripts/operations.mjs. Native password sign-in is kept.export,importandresetmove or clear local data. - Installation archives are refused in build output and are never served by the local app.
Changed
- Use Node.js 22.20.0 and pnpm 10.12.4. (0.3 used Node.js 26.8.1 or newer.)
- Apply the ten additive migrations
0110_move_in.sqlto119_local_portability.sql, in order, before the updated Worker serves traffic. They leave earlier migrations and existing rows unchanged.
Upgrading from 0.3.x
Back up first: locally .wrangler/state and .dev.vars; on Cloudflare the D1
database, every R2 object and your secrets, including INTEGRATION_ENCRYPTION_KEY.
Update your checkout, switch to Node.js 22.20.0 and run pnpm exec rer setup
with your existing owner email. It applies the migrations and keeps your owner,
password, data and saved settings. Never use reset to upgrade.
Upgrading from 0.3.x lists every step.
Known limits
- Accessibility is on a confirmed owner HOLD: an automated checker wrongly accepted four contrast cases. No WCAG conformance is claimed.
- Backups and archives cover D1 and R2 only. Durable Object storage is not included, and full portable-storage fidelity (including resizable ArrayBuffer preservation) is not established.
- Hosted operating costs are unmeasured. Timed activation and paid-provider (model and mail) execution are not qualified.
- Move in and the connection protocols are qualified with synthetic fixtures only; real vendor exports and live Slack were not supplied.
- No hosted installation, compliance or FedRAMP qualification is claimed.
- The hosted service at app.happytohelp.com is separate legacy production. It is not part of this release and is not upgraded by it.
0.3.0 — 2026-10-10
-
Hand assistant replies and attachments to the editable composer, close compact panels and focus the draft; keep desktop columns open and Send explicit.
-
Adopt completed local reply attachments as the current operator's native media before filling the composer. Repeated Use keeps one file; revoked authority, changed conversations and incomplete copies leave a visible error. Ordinary Send preserves the copied bytes through the native message path.
-
Make delegated Codex structured output strict at every object, including unused reply and attachment fields, while preserving authorized legacy reply delivery.
-
Keep native model-provider HTTP status and a bounded, redacted error excerpt on failed delegations so operators can inspect the failure after reload. Provider failures remain terminal and never send a reply or replay work.
-
Persist shared public appearance through native settings, with widget/Help Center parity and visible loading, error, offline and recovery states. Long public names, multiline greetings and unbroken article text wrap within their surfaces; wide article code and semantic tables scroll within named, keyboard-focusable regions with visible focus rings inside the content column.
-
Let keyboard users focus and scroll the chat transcript, including long welcome greetings, with a visible focus ring and a tab path back to the composer.
-
Add explicit, scanner-safe native email sign-in with hashed short-lived one-use tokens, current authority checks and safe native return destinations.
-
Exercise the real paired connector through native repair, a reviewed draft and operator Send, including visitor socket delivery and stable reload identity.
-
Adopt the unchanged Base delivery producer pinned at
d6a1bd83ee80ec3d603ded2c067d4c504d8a2bf5; builds emit schema-2 manifests and raw payloads. Preserve exact candidate payload bytes and deployment policy.
Real provider and hosted acceptance remain separate; the historical accessibility checker HOLD remains in force.
0.2.2
Added
- AI answers carry publication-bound citations. Retrieval excludes unpublished or withdrawn sources, and stored citations retain the source version used for the answer.
- The empty inbox and Setup page share an observed, project-scoped eight-step activation checklist. Saved settings alone do not count as delivery, DNS, model, inbound-mail or widget proof; unknown provider outcomes are never replayed.
- Knowledge authoring exposes article publication, retrieval eligibility and source navigation. Conversation AI controls share one state, demo workspaces retain their context, and the spend card explains effective runtime ceilings.
- Migration
0107_activation_receipts.sqladds activation observations;0108_public_answer_citations.sqladds publication identities, retained citation sources and customer-context mutation fences. The upgrade also includes0105_edition_delegation.sqland0106_project_verification_secret.sqlafter public v0.2.1. - Pending invitations on Agents can be copied, resent (when email is configured) and revoked by
owners and by admins for agent invitations. The routes re-check the caller's role. New public
helpers
GET /api/identity/auth-optionsandPOST /api/identity/link-status, withpnpm run test:identity-browser,tests/identity-links.mjsandtests/management-invitations.mjs.
Qualification boundary
- Cited answers and the activation checklist are implemented. The real timed activation recording is still missing; recorder preparation is not a pass.
- Accessibility remains FAIL / confirmed owner HOLD because the retained checker has false accepts and timing/background limitations. No complete WCAG conformance is claimed. Further checker correction remains held.
- Local tests and a version number do not establish hosted, live-provider, production-import or portable-storage fidelity acceptance. Exact release receipts remain in maintainer custody outside the public source.
Fixed
- Widget settings (Theme, Texts, Settings) now show what the widget actually renders:
default colors, default copy and default toggles, with the default copy also shown as
each text field's placeholder. Editing one field changes only that value in the form
and the live preview, and Save stores only edited fields, so saving without edits no
longer blanks the widget copy, turns defaults off or paints colors black. Clearing a
text field or restoring a default removes its override. Saving widget settings no longer
discards the theme and text when the form includes a
settingssection. - Every project now has a server secret (
H2H_SECRET) for signed-in-user verification. It is generated when a project is created (setup, registration, project creation, demo inbox) and migration0106_project_verification_secret.sqlbackfills existing projects that had none. Owners and admins can reveal and copy it from Widget > Code; other roles see an explanation instead of disabled buttons. GET /api/identity/projects/:idreturns only the project's id, name, widget key, allowed origin and creation time; the server secret reaches owners and admins only through widget settings.- The delegation consent page and Connected applications are served under a strict
Content-Security-Policy (same-origin sources, no plugins,
base-uri 'self', no framing) andform-actionlimited to this origin plus, on the consent page, the callback registered for the request's client. The consent page keepsX-Frame-Options: DENYandno-store; the application header layer no longer replaces thatX-Frame-OptionswithSAMEORIGIN. - Every destructive delete in the management and library screens (saved reply,
contact, AI assistant, plugin, agent/member, article, category and website
dataset) now asks through one shared, accessible confirmation dialog instead
of deleting at once or using a native browser prompt; Tab and Shift+Tab stay
inside it. Contact erasure uses the
same dialog with its exact typed
ERASEconfirmation. The last owner cannot be removed, and removing yourself is called out before it is confirmed. - List tables on phones (saved replies, agents, contacts, plugins, websites, articles) stack each row as a captioned card, so no column or row action is hidden behind an unnoticed sideways scroll; row actions that sit in a ⋮ menu on wide screens are shown as visible controls on the card.
- The evaluation-run form shows field-level messages in place of the browser's JSON parser text, has an empty state, one consistent name (“Evaluation runs”) and explains its limits (a maximum cost of 0 is not accepted; 1 to 32,000 tokens).
- Website datasets refuse crawl depths outside 0 to 100 and page limits outside 1 to 10,000 in the form, the API and the crawler start; contacts created from the dashboard or API must have a name, an email or an external ID.
Changed
-
The owner-approved “Customer Support, Solved.” homepage clarity pass (owner direction 2026-10-02) keeps the 1, 2, 3 story and cuts everything that stood between a reader and it. The hero drawing is one column: Maya cannot turn on the Spanish version of her store, Codex has fixed it (a cyan note card with a check), and the reply is in the composer with Send circled, with callouts 1, 2, 3 and the caption steps; the subhead is “Your Codex or Claude fixes the problem and writes the reply. You press Send.” and the line under the actions is “100% free and open source.” “Not just better. Free.” now says it plainly (100% free and open source, free as in code and free as in cost, MIT licensed, “No seats. No plans. No fees.”) beside a drawing of the MIT licence. “Help before they ask”, “The rest of your support desk” and “Try it beside what you have” are trimmed to one short line each with smaller drawings, and a short “Ready when you are.” band replaces “Yours to run”. The page no longer mentions prices, hosting, providers or Run Edit Run, and the examples strip, the signals list, the bill, installer and Local panel drawings, and the costs and hosted-options links are removed. The page meta description is updated.
-
Historical pre-clarity homepage state: the page then led with the local-agent handoff; its hero drew a conversation whose task Codex or Claude on the team's own computer had already completed, with the Local panel, internal note and drafted reply the team reviewed, and a subhead that said who ran it and who approved sending. “Help before they ask” then followed the hero, followed by the four product parts. The “Your own agent can investigate” section was replaced by a short “How the handoff works” detail built from the New task form. All drawings mirrored the real interface wording.
-
Historical initial homepage approval (owner approval 2026-10-01; superseded by the 2026-10-02 clarity pass): the page at that point was described as the “Customer Support, Solved.” page with a drawn inbox hero, the four product parts, “Help before they ask”, “Your own agent can investigate” and “Yours to run”, set in Outfit on warm paper with colour only inside labelled HTML/SVG drawings. Outfit was self-hosted from public/fonts/outfit/ under the SIL Open Font License 1.1, so the page made no third-party request. This preserves the initial approved state; the current page is described by the clarity-pass entry above.
-
The public identity pages (
/login,/register,/forgot-password,/reset-password,/verify-email,/accept-invitationand the completed-setup state of/setup) use the homepage's paper, ink and Outfit with the HappyToHelp wordmark, a link home and links to one another, instead of the dashboard-styled form. Invitation, verification and reset links are checked on load and report a missing, invalid, expired or used link with a way forward. A signed-out invitee sees the workspace and email and either creates an account or signs in and returns to the link. Every new-password field states and enforces the 12 to 1024 character rule./loginpoints to/setupwhile no owner exists; sign-up is offered only when it can work and stays closed until setup is done; forgot-password without an email provider still fails closed and says the workspace owner must reset the password. -
Local computers and delegation use the workspace design system. The Connect computer dialog is styled outside the inbox; authorizing a computer shows “Computer approved” or “Request denied” and clears the code; Connected applications and the connection consent screen render in the application shell instead of bare server HTML, cancelling a connection returns to Connected applications, and missing, invalid, unavailable or signed-out requests show friendly pages. The consent form and revocation rules are unchanged. Registering a client whose identifier already exists now answers 409
CLIENT_EXISTSinstead of a server error. URLs keep text that reads as a number (an OAuthstate, a device code) exactly as written.
Removed
- The previous illustrated homepage: its components, styles, scroll-parallax
hook, its artwork under
public/homepageand their provenance entries.
0.2.1 — 2026-09-27
Fixed
- Hosted Assisted and Managed builds (the hosted options from Run Edit Run) no
longer fail with
pnpm: not found. Run Edit Run's trusted project build provides Node but no global pnpm, and the package scripts thatbuildandverifyrun callpnpm. Therer-project.jsonbuild and verify commands now put the pnpm 10.12.4 thatscripts/independent/setup-build.mjsinstalls in.rer-toolsfirst onPATH. Standalone installation and thepnpm runscripts are unchanged. - The
rer-project.jsonartifact check no longer fails with97 !== 94.tests/independent-runtime.mjsstill requires an exact table count, now 97: migrations0102_public_abuse_limits(abuse_counters) and0103_contact_erasure(contact_erasures,contact_erasure_objects) in 0.2.0 added three tables that the expected count had not been updated for.
0.2.0 — 2026-09-25
First public source release of the self-hosted edition: the version of HappyToHelp you install and run yourself.
Added
- Native TypeScript rewrite on Cloudflare Workers: TanStack Start/React pages, Hono API, D1 records, R2 files, Queues for background work and a Durable Object for live conversation delivery, replacing the original PHP/Laravel and AWS services.
- The original dashboard, customer widget, AI assistance and suggestions, knowledge base with published help centers, customer context, local-agent delegation, training/evaluation runs and integrations (email, GitHub, help center imports, brand images and website preview), ported to the new Cloudflare runtime.
- Village public homepage with layered, reduced-motion-aware artwork. (Replaced on 2026-10-01 by the “Customer Support, Solved.” homepage; see 0.2.2.)
- Standalone browser installer (
node scripts/install.mjs) for local or Cloudflare installation, with agent-assisted prefill. - Fictional demo inbox for trying the workspace without real customer data.
- Local importer for exports from the original HappyToHelp service.
- Contact erasure for owners and admins, from the dashboard (Erase personal
data…) or
POST /api/management/projects/:projectId/contacts/:contactId/erase. It removes the contact's identity, messages' content, attachments (including R2 objects), customer context, AI and delegated-work text, inbound email evidence and legacy import copies, keeps transcript order, and records a non-identifyingcontact_erasurestombstone. docs/PRIVACY.md describes what is stored, what goes to which provider, and what erasure cannot reach.
Security
- First-owner setup fails closed. Only loopback development may create the first
owner without a private
H2H_SETUP_TOKEN. A remote deploy of a fresh installation refuses to publish without a token of at least 32 characters, and a Worker reached any other way answers owner setup with HTTP 503 until one is configured. - Operator pages and API responses send
Content-Security-Policy: frame-ancestors,X-Content-Type-Options: nosniffandReferrer-Policy: strict-origin-when-cross-origin; published Help Center pages stay embeddable. - The dashboard parses user agents with
ua-parser-js1.0.41 directly, replacing a wrapper that pinned a release affected by a high-severity ReDoS advisory (GHSA-fhg7-m89q-25r3). - Automatic inbound mail (autoresponders, bounces, list mail) is labelled and
never triggers an AI reply or a notification. Notifications sent through
Resend or SendGrid carry
Auto-SubmittedandX-Auto-Response-Suppressheaders so that other systems do not answer them automatically. - Public widget, registration and project-creation requests are rate limited
per visitor, conversation, client address and account, with counters in D1
(
RATE_LIMITS). Per-project ceilings on widget sessions, conversations and attachments bound what rotating client addresses can create. A refused request gets HTTP 429 withRetry-After. - Automatic AI work that visitors can trigger has daily ceilings per project
(replies, estimated spend, context runs) and across the installation
(
AI_DAILY_CEILINGS). Past a ceiling, visitor messages still reach operators, the skipped reply is shown in the transcript, a visitor's explicit reply request gets HTTP 429 until 00:00 UTC without the operator-only reason or spend, andGET /api/dashboard/projects/:projectId/ai-usagereports the day's usage. See docs/PUBLIC-LIMITS.md. - A reply request's
requestId(widgetrequestcommand, dashboardrequestaction) must be a UUID, or the request gets HTTP 400, so no caller-chosen text becomes a generation ID that contact erasure keeps.
Fixed
- The scheduled outbox replay no longer leaves a conversation undelivered after a failed, queued or uncertain AI generation for an email message.
- Revoking a paired computer or its grant withdraws authority without claiming that the local run stopped: started work ends as revoked with an unconfirmed local outcome, and the conversation can be delegated again at once.
Changed
- Licensed under MIT for the whole repository, including artwork.
- Dashboard styles are first-party, built on Bootstrap 5.3 (MIT) with icons from
the
feather-iconspackage (MIT); no commercial theme, font or image is used. - The delivery artifact is byte-reproducible from a commit with the declared
Node and pnpm versions (
pnpm run test:reproducible-build). pnpm run verifyincludes a first-release journey test against a Worker built from the source and run locally, and continuous integration runs it with every browser suite and the homepage and public-site checks on pushes tomainand on pull requests.
Contract source before 37d807e8cf269f85484e4af19558f1460b7345eb
HappyToHelp product contract
Target edition · 17 October 2026 · US-first, USD. HappyToHelp is a complete customer service help desk and AI support agent for a US SMB support lead switching from Zendesk, Intercom (with Fin), Help Scout or Freshdesk. It owns the job from customer intake through a shared operational queue, self-service and live business context to an authorized resolution and continued customer recovery. Decagon, Sierra and Pylon set the agent/procedure and B2B-channel baseline; the target goes further with verified repair and obligations that survive handoffs.
This is the product we are building towards. Required behavior is not a claim of current implementation, provider acceptance or compliance. The final table records current code/test coverage as done, partial or missing; each clause names the public journey that will prove it. The matching evidence map is ACCEPTANCE.md. A cited test is implementation evidence, not a claim that it was executed for this document change.
Keep the owner-approved homepage, UI and behavior intact. The retained owner decisions of 8 October (native passwords), 9 October (import equality and bounded ordinary HTTPS transport) and the detailed PUBLIC-001 specification remain in force. This contract expansion authorizes future build rounds against the missing work; it does not silently change today's marketing claims. The product remains editable source on Cloudflare Workers with a separately authorized local connector, run through rer.
Product target
HappyToHelp is the complete help desk and AI support agent a US SMB support lead buys instead of Zendesk, Intercom (with Fin), Help Scout or Freshdesk; Decagon, Sierra and Pylon set the agent and procedure baseline it must also meet.
| Category | Customer service help desks and AI support agents |
| Incumbents a buyer switches from | Zendesk, Intercom (with Fin), Help Scout, Freshdesk (agent baseline: Decagon, Sierra, Pylon) |
| First buyer | A US SMB support lead, costs in USD, moving a Zendesk, Intercom, Help Scout or Freshdesk help desk |
Retained product and operating guarantees
-
NATIVE-001 — Native owner installation. A clean owner can inspect the operating description before installing dependencies, install locked source, prepare local or selected remote bindings/migrations, build, verify and deploy through
rer. Local setup exits with no app running; dev prints a privateRER_OPENaddress that enters as the real local owner through the rer dev v2 boundary, preserving native sessions, roles and passwords. Reset is explicitly confirmed and local; export/import preserve supported native data with documented exclusions. Deployment dry-run makes zero outbound requests and explicitly reports that fact. A separately and explicitly started read-only provider preflight uses the owner's scoped Cloudflare token with owner consent to read the account's Workers subdomain and the Worker's settings and secret names (three GETs for an existing Worker); it sends no mail and changes no resources. Dry-run and preflight are independent steps, neither a mock of the other. The delivered runtime requires no original checkout or PHP service.Acceptance evidence: Use a clean checkout through rer describe/check, locked installation, setup, dev, verify, reset and export/import; preserve owner/data/settings and refuse unconfirmed destructive work. For deployment dry-run, assert zero outbound requests and an explicit no-outbound report without provider credentials. As a separate acceptance point, explicitly start the read-only provider preflight with owner consent and the owner's scoped token; assert only the three expected Cloudflare GETs for an existing Worker, no mail and no mutations, and refuse missing credentials or consent. Prove the runtime works independently of the original checkout; separately qualify remote provisioning.
-
IDENTITY-002 — Retained native password identity (owner decision 2026-10-08). Preserve native password sign-in, first-owner setup, the accepted owner experience and prior account/workspace data with the maintained Base command mechanisms. Retain this edition's authentication and native owner setup. Existing tenant and permission checks continue to govern every session. A second factor for these native accounts is required by IDENTITY-003; it adds to native passwords and never replaces them.
Acceptance evidence: Complete native password setup, login, recovery and workspace re-entry, then upgrade with prior owner credentials and data intact; configured providers must not replace native identity.
-
IDENTITY-001 — Scoped authority. Owner setup, registration, login/recovery, project switching, membership and widget admission establish native identity. Every private read/write enforces the current actor/project/role; blocked or deleted projects and revoked credentials lose access. Provider configuration never substitutes for user authority. The public widget key and origin are not a secret: visitor, registration and project-creation requests are bounded by D1-backed limits (
RATE_LIMITS) and refused with HTTP 429 andRetry-After.Acceptance evidence: Through native session and widget routes, deny cross-tenant, blocked/deleted and revoked access; prove public admission returns 429 with Retry-After when limited and provider configuration conveys no actor authority.
-
FIRST-RUN-001 — A useful first workspace. First-run setup is one screen: the owner's email, a password, the website and, only where the server requires one, the private setup token. Missing names and colors are derived and every derived value can be changed. A completed installation leads the owner to a workspace that is already set up, whose Setup page lists only what cannot be done for them (an AI service key, the widget on their website and, with a hosted email provider, a verified sending domain), leads with the widget, lets the owner skip any of them for now, and shows everything else under "What we've set". Every workspace created by first-owner setup, signed-in workspace creation or email-verified registration, and never a demo workspace, is provisioned in one step: a starter assistant as its default visitor assistant, a reply-by-email mailbox when the installation holds
INBOUND_EMAIL_TOKEN, and mail sent from the installation sender until the workspace's own domain is verified. The starter assistant answers visitors by itself once a provider key exists, within the daily AI ceilings; with no key no assistant is assigned to a new conversation, it stays with the team and the AI page and Setup say a key is missing. The first-run Create workspace action may send one welcome email to the owner; an uncertain send is never replayed. Ordinary workspace creation leads with the widget snippet; Advanced retains the server secret and verification examples. Empty inboxes offer installation, a link to Setup and a demo. Workspace headers follow workspace switching. Visitor headers retain the operator's display name.Acceptance evidence: Run fresh first-owner setup and signed-in workspace creation to Setup and an installable widget; inspect derived editable name/color, starter assistant, mailbox/sender, skip/Advanced controls and mobile headers. With no model key a new visitor stays with the team; with a configured provider exercise the capped starter. A workers.dev hostname must not become a business name.
-
LOCAL-MAIL-001 — Rer dev mail. Trusted local development configuration uses the rer dev v2 development transport: it validates and suppresses visitor and teammate mail, reports
development, stores no messages and exposes no mail viewer. It sends no external email and never claims delivery. The local owner enters automatically through the dev boundary; native password identity, ordinary hosted email-link confirmation and prior stored data are retained. Production has no local dev surface. Missing credentials or failed remote delivery never select a local substitute.Acceptance evidence: Enter through rer dev v2; send visitor and teammate mail and prove development suppression without storage, viewer or external send; refuse forged and production dev entry and never substitute suppression for a failed hosted provider.
-
CONVERSATION-001 — Durable transcript. Customer, operator, generation, import and administrative writers preserve stable message/command identity, revision/frontier, attachment ownership and final-reply admission atomically. Competing or repeated writes cannot admit two incompatible final replies. Owner/admin contact erasure removes message content while keeping identity, revision and frontier, so erased transcripts stay coherent.
Acceptance evidence: Race visitor, operator, model and import writers through conversation routes with duplicate and lost responses; admit only compatible final replies. Erase a contact through the owner door and verify coherent identity/revision/frontier with content removed.
-
DELIVERY-001 — Live delivery and recovery. Persist before broadcast; reconnect/outbox replay and socket authorization recover committed messages after reload, disconnection or process wake. Provisional AI deltas never become durable final answers until guarded admission succeeds.
Acceptance evidence: Disconnect/reconnect widget and operator sockets after persisted writes, restart the runtime and recover the same committed messages/attachments; unauthorized replay is denied and superseded AI deltas never become final replies.
-
UI-001 — Existing editable experience. Reuse the original React dashboard, transcripts/drafts/suggestions, settings and Shadow DOM widget; preserve useful desktop/mobile flows, attachment display, collector/privacy controls and errors. Native routing and transport use the configured application origin.
Acceptance evidence: Use the native dashboard and separately installed widget at 1440 and 390 pixels with realistic conversations, attachments, drafts, errors and workspace switching; retain the approved desktop/mobile navigation and configured-origin transport.
-
MOVE-IN-001 — Reviewed history import. Current workspace owner/admin reviewers privately upload, inspect per-kind plans, source-located omissions, rejections, conflicts and publication changes, then explicitly apply bounded, resumable imports of conversations, contacts, tags, saved replies and articles. Preserve source identities, timestamps, private notes and publication state; reject unsupported meaning rather than inventing it. Recheck current role and workspace authority for apply, resume and whole-import undo. Retain immutable source custody and conflict-safe reversal journals. Imports and undo send no mail, widget messages, model requests, assignment or connection notifications; imports are excluded from Reports. Native tag controls enforce workspace scope. Owner decision 2026-10-09 requires exact business-state repeat/undo equality, including contacts, conversations, messages, private notes, tags, source links and every other imported business table. Only platform counters/sequences, audit history and import journals are excluded. Synthetic 1,000-conversation datasets for Zendesk and Help Scout qualify this local flow.
Acceptance evidence: Through Move in, exercise all five kinds, source custody, per-row omissions/rejections/conflicts, current-role denials, inert apply/resume/repeat/undo and exact business-state equality for synthetic 1,000-conversation Zendesk and Help Scout datasets; counters/sequences, audit and journals are the only named exclusions.
-
OUTCOMES-001 — Resolution feedback and provenance. Current original visitor sessions may rate a closed resolution with thumbs up/down and an optional comment up to 1,000 characters. Changes retain history; reopened cycles cannot receive the previous resolution's rating. Operators retain access to each past resolution's latest feedback after reopening; visitor eligibility and report denominators remain tied to the current cycle. Erasure removes rating comments. Confirmed operator-sent drafts establish assisted outcomes, otherwise confirmed human replies establish human outcomes. AI requires a complete visible answer history without a person handoff; missing evidence remains unknown. Status, assignment and cancellation transitions recheck current authority atomically.
Acceptance evidence: Close, rate, rerate, reopen and close again via widget/operator routes; prevent previous-session/cycle feedback, retain old-cycle operator visibility, redact erased comments and verify human/assisted/AI/unknown attribution from actual visible answers.
-
REPORTS-001 — Workspace calendar reports. Native conversations created in the workspace IANA calendar range with at least one persisted message form the cohort; Move in and legacy imports are excluded. First visitor-to-visible-answer response and creation-to-first known-resolution durations use median and nearest-rank p90. Each conversation contributes its latest closed cycle once to outcome and satisfaction rates. Reopened conversations leave those denominators. Aggregate queries return bounded data; CSV streams every matching conversation with formula-safe cells. Empty widget conversations stay durable but are excluded from Reports and its analytics CSVs. A separate step-up guarded JSON export includes all workspace conversations, messages, private notes and attachment names across dates and imports; attachment bytes stay in the portable backup.
Acceptance evidence: Compare Reports and formula-safe CSV to hand-calculated response/resolution median and p90, latest-cycle outcome and satisfaction cohorts across DST and tenants, including more than 10,000 rows and excluded imports/reopened cycles.
-
CONNECTIONS-001 — Workspace integrations. Owner/admin tokens have explicit scopes, optional expiry, one-time display, hashed storage and durable audit. Bearer-only API calls have no CORS, per-token limits and native guarded writes. Contact erasure fences API identity restoration and pending event payloads. Native events commit tenant-bound webhook and Slack intents; historical import apply and undo do not emit them. Slack projects bounded native visitor text through Base escaping. Base owns signing, durable attempts and retry policy. HTTP 500 stays uncertain and is not replayed; 429 retains bounded retries. Scoped edition override, owner decision 2026-10-09: this consumer uses ordinary platform HTTPS fetch through the unchanged Base wire interface. It refuses every 3xx with manual redirect handling, enforces a 10-second timeout, a 1 MiB request limit and 64 KiB streamed-response limit. Destination syntax and literal IP validation remain enforced. This expressly overrides Base's transport DNS-pinning requirement for this edition; it does not claim DNS pinning or change copied Base contracts. Local synthetic protocol checks do not establish a live Slack connection or hosted installation.
Acceptance evidence: Issue, use, expire and revoke each scoped show-once token; exercise native API operations, erasure fences, signed events and Slack escaping. Refuse redirects/unsafe literal destinations and over-limit traffic; preserve timeout, streamed bounds, uncertain 500 without replay and bounded 429 behavior under the recorded HTTPS override.
-
ACTIVATION-001 — Observed owner setup. An owner sees the durable, project-scoped eight-step list on the Setup page; the genuinely empty inbox shows one next action and a link to it, and loads none of it. A step is confirmed only by an observation, never by a saved configuration, an installer default or a preset, so a workspace with nothing observed yet is zero of its applicable steps. The system runs its own checks: while an owner is signed in the page asks the server to observe, bounded by freshness windows. These checks are non-generative metadata, domain and DNS reads and never send mail. They distinguish saved configuration from observed sender DNS, authenticated model metadata, an inbound receipt, effective runtime ceilings, allowed origin and an authenticated widget ping; whether an article is published is not one of them (that step stays among the eight ids but is hidden and never counted). Mail to the owner is confirmed by a used emailed sign-in link, or by the provider's reported outcome for the welcome or test email; local development mail is suppressed and never confirms delivery, and provider acceptance or queueing is pending.
GETperforms no provider work and writes nothing. Only an explicit owner action (Create workspace, or Send me a test) may send mail, to that owner's mailbox, with durable identity; ambiguous work is never replayed. Missing provider permissions and unsupported status APIs remain unavailable. Configuration changes invalidate observations; model and DNS validation expire after 15 minutes and every observation shows its time. The owner can skip an owner-only step (the widget, the AI service, the sending domain) for now, and undo it. A skip is stored on the server for the workspace, can be made by an owner or admin only, makes no provider request, and moves the step out of Needs you and out of the confirmed count and its total; a skipped step is never shown as confirmed. An observation always wins: a skipped step that is later observed is confirmed and counted, and a rejected provider key stays under Needs you whether or not it was skipped. Provider keys and their fingerprints never enter API responses or browser storage.Acceptance evidence: Read Setup without side effects, observe fresh/expired/rejected configuration and explicit provider outcomes, skip/undo owner steps and reload. A skip or preset never counts as confirmation; local suppression never proves delivery; keys/fingerprints remain server-only and uncertain explicit test/welcome mail is never replayed.
-
AI-001 — Configured model execution. Retain Ensemble model selection, context/tools, streamed events, normalization, raw per-round provider usage, attribution, bounded suggestions and reply lifecycle. Missing providers fail explicitly when AI is asked for, and a default assistant whose provider has no key is simply not assigned to new conversations; uncertain provider attempts remain uncertain and are not replayed automatically. Usage is diagnostic/provider accounting data, not an active payment, balance or debit system. Visitor-caused automatic AI work is capped per UTC day per project and installation (
AI_DAILY_CEILINGS); a skipped reply is recorded as terminal and never replayed.Acceptance evidence: Request configured suggestions/replies through native routes; inspect normalized streaming events, per-round usage, context/tool and budget bounds, explicit missing-provider errors and durable daily-cap skips; crash/ambiguous attempts must not automatically replay.
-
KNOWLEDGE-001 — Published knowledge. Dataset ingestion/crawl, retained corpus, lexical/selected semantic retrieval, citations and article/category authoring maintain project scope and publication state. A failed refresh cannot replace the last usable published corpus. Public pages exclude drafts/deleted projects and preserve original canonical article/search routes.
Acceptance evidence: Publish and search articles/categories through authoring and public help-center doors; deny draft/deleted/cross-project access, verify citations and canonical links and retain the last usable published corpus after a failed refresh.
-
CONTEXT-001 — Attributed customer context. Profiles, monitoring, insights and context packets preserve evidence attribution, source bounds, consent and project ownership. Provider output must satisfy the selected schemas before becoming usable customer context.
Acceptance evidence: Generate/read profile, monitoring, insight and context packets through native routes; reject ungrounded/schema-invalid or cross-project content, preserve attributed evidence and respect consent/source bounds.
-
DELEGATION-001 — Explicit local authority. Pairing, devices/grants, revocation, tool context and work/result states preserve investigation, resolve and advance-authorized resolve-and-reply distinctions. Revocation withdraws authority and never asserts that a local process stopped: started work becomes terminal with an unconfirmed outcome, and only the device may report cancellation. Local processes remain in the optional connector, never an implicit Worker capability.
Acceptance evidence: Pair the packaged connector, investigate, separately authorize a child fix, obtain a distinct read-only observation and use human Send with exact-request replay. Refuse stale/revoked/offline/unverified/uncertain work and distinguish resolve from advance-authorized resolve-and-reply; revocation cannot assert process cancellation.
-
TRAINING-001 — Durable evaluation. Training and evaluation preserve run/case state, model/budget selection, raw provider usage and cancellation/recovery. Synthetic data admission is explicitly local/test-only. Historical pending attempts require reconciliation; a fixture pass is not live-provider quality acceptance.
Acceptance evidence: Create, run, cancel and recover persisted evaluations through training routes with model/budget selection and raw usage; reconcile historical pending/uncertain attempts and keep synthetic admission local/test-only, with live quality qualification separate.
-
INTEGRATION-001 — Honest external effects. Email/inbound mail, GitHub, branding and knowledge imports use configured native adapters, tenant-scoped credentials, durable identity and ambiguous-outcome handling. Website previews use a separate origin, scoped expiring grants and public-network restrictions. Machine-generated inbound mail never triggers autonomous AI replies, notifications or outbound email; its classification is recorded before admission and survives recovery and redelivery. The
email:message local-id prefix is reserved for inbound claims and refused by the message API. Shopify, Stripe and CRM support actions are required by COMMERCE-001, BILLING-001 and CRM-001. HappyToHelp never holds funds or becomes a payment processor; historical imported balances remain custody records, not executable authority.Acceptance evidence: Use configured email, inbound mail, GitHub and knowledge-import public doors; test idempotency, machine-generated-mail suppression, separate-origin preview grants and network denial. An operator reply emails the visitor even with an online/unverified widget; a visitor address matching the reply sender is intentionally excluded and the message status explains that cause. Test accepted, failed and uncertain outcomes without invented delivery; business-action evidence is also required by COMMERCE-001, BILLING-001 and CRM-001.
-
PUBLIC-001 — Public product source. The approved homepage (owner approval 2026-10-01, clarity pass 2026-10-02, hero redesign 2026-10-08, hero leading with help before they ask 2026-10-20) is the real public
/experience, in this order: the hero, whose headline “Knows what your customer needs before they do.” stands left-aligned beside one hand-drawn picture of both moments on a pale aqua blob, joined by an aqua pen arrow: 1, a checkout page in its window with the widget's offer card (signed with the speech-bubble mark) floating over its corner; 2, a conversation already solved (a customer, Maya, cannot turn on the Spanish version of her store; the agent's fix, beside a code glyph, says it is fixed; the reply to Maya carries Send inside it, the only step left), each numbered on a filled aqua disc; with the subhead “Some customers who get stuck never write in. They just leave.”, the line “100% free, open source alternative to Zendesk, Intercom, Help Scout and Freshdesk”, an aqua pen-stroke flourish under the calls to action that draws itself in once, and under the picture the captions “Before they ask” (“When someone seems stuck, the widget offers a hand.”) and “When they ask” (“Your Codex or Claude fixes the problem and writes the reply. You press Send.”) on filled aqua number discs; “Not just better. Free.” (100% free and open source, free as in code and free as in cost, MIT licensed, “No seats. No plans. No fees.”, each promise after a line icon in a pale aqua circle, with the MIT license drawn as an ink card over a wordless code editor, “free of charge” and the rights highlighted in aqua); “The rest of your support desk” (chat widget, shared inbox, help center, suggested replies, as frameless ink cards numbered on filled aqua discs); “Try it beside what you have” (install, bring the help center from Zendesk, Intercom or Freshdesk, add the chat widget, on filled aqua discs, beside the finished import in its window); “Ready when you are.”, a big closing headline with an aqua pen line drawn under it; and the footer, signed with the header's lockup. Below the hero the drawings carry the hero's language: each floats on a pale aqua blob, the mark's three aqua sparks spring from the corner of four of its cards, a window frame stays only for the code editor, the checkout and the import, the text links carry the hero's aqua underline, and a full-width aqua pen line with one loop divides Free from the desk and the desk from Try it beside what you have. The page carries no price, hosting or provider line and no plug for any other service. The drawings mirror the real interface and make no claim the product cannot back; conversation, ticket-history and automation import, reporting and compliance claims are deliberately absent. It is a warm off-white page in one geometric sans-serif (Outfit, self-hosted frompublic/fonts/outfit/, so the page makes no third-party request, over a metric-matched local fallback, so no text moves when it loads) with near-black ink and black pill buttons; color appears only inside the drawings, which are labeled HTML/SVG rather than raster images, and in aqua accents outside them (the hero's and the desk's number discs, the promises' circles, link underlines, the hero flourish, the dividers, the closing line) and in the sparks of the speech-bubble mark beside the header and footer wordmark. The wordmark is not set in Outfit: it is drawn by hand as round-capped SVG strokes following Nunito's letter shapes (SIL OFL), with no font data embedded, and the link it sits in is named HappyToHelp by visually hidden text. The page's text and real links, derived frompackage.jsonrepository.url, are ordinary DOM content; the hero flourish draws in once as the page appears, and each moment below the hero (a drawing, the promises, the steps, a desk card, a divider, the closing line) plays once, in under 1.8s, as it scrolls into view (an IntersectionObserver), moving only opacity, transforms, clipping and strokes, so nothing shifts; reduced-motion preferences remove all animation, transitions and smooth scrolling without changing layout, leaving every drawing in its final state and every stroke fully drawn./docsrenders, at build time, the Markdown files listed indocs/site.json, in the homepage's paper, ink and Outfit, with section navigation, page contents and GitHub links for everything unpublished; an unknown page gets the branded 404. Every build renders the current files, and an unlisted Markdown file fails verification. Dynamic published help centers retain project scope, canonical links, search and draft/deleted denial. The customer widget remains available through owner-configured installation; broader marketing routes, pricing, legal, referrer, waitlist and public auto-widget behavior are outside this edition.Acceptance evidence: Exercise the approved homepage and /docs requirements retained in this clause and the detailed acceptance specification at desktop/mobile, including keyboard/reduced motion, published Markdown manifest/link validation and draft/deleted help-center denial; target requirements do not authorize changed marketing claims.
-
MIGRATION-001 — Prior-data custody. Explicit legacy artifacts preserve IDs, exact historical financial values, transcripts, object hashes, publication and permissions through resumable guarded D1/R2 import. Historical financial SQL, imported rows and reconciliation holds remain immutable archive custody; they never become active payments, balances or provider work. The one exception is an explicit owner/admin contact erasure: it takes precedence over archive custody for that contact's personal data and redacts the imported rows and their verbatim archive copies (row digests are kept, so replaying the bundle does not restore them), leaving a
contact_erasuresaudit tombstone. Old credentials do not become trusted native authority.Acceptance evidence: Import representative legacy IDs, permissions, exact historical financial values and media hashes through local D1/R2; resume safely and refuse conflicts without external work. Erase an imported contact and prove archive redaction plus tombstone/digest fencing prevents restoration of erased personal data.
-
SOURCE-001 — Author-owned capability graph. The edition selects maintained source with inspect/check/lock/release commands. Shared capabilities include substantial implementation, migrations and meaningful tests; a second consumer preserves its own policy. Release excludes credentials/private fixtures and retains asset provenance/licensing obligations. Original work is preserved.
Acceptance evidence: Run inspect/lock/check and offline Base-copy verification on staged intentional source, exercise origin/drift/mode refusals and release only the selected licensed tree without credentials or private fixtures; source custody alone is not product acceptance.
Gap: The authoring CLI and source-integrity checks exist and the capability graph is maintained.
tests/helpers/installer/edition-authoring.mjs, editionAuthoringJourney, runs inside the existing release-artifact test intests/journeys/installer.mjs(Verify runtime-and-identity shard). It exercises CLI origin, local drift and executable-mode refusals, selected licensed release, excluded local credentials/private fixtures, clean-source refusal and receipt verification. Source integrity does not assert a product build or deployment; exact-SHA Verify remains required.
Target clauses
Complete support operations
-
DESK-001 — The shared support desk. A visitor starts website live chat, identifies themselves under the workspace policy, sends files and returns to their history. Humans see one durable shared inbox with customer history, scoped retained-history search with words, quoted phrases and literal customer-identity matching, open/closed/mine/unassigned/AI/tag filters and saved replies that insert into the composer without silently sending. Ticket status follows the STATUS-001 lifecycle and saved replies extend to MACRO-001 action macros. Replies, attachment downloads and errors are visible on both sides; privacy/collector controls remain effective.
Acceptance evidence: Through the installed widget and operator inbox, exchange messages and real attachment bytes, search/filter the resulting queue, insert and edit a saved reply, reload both sides and deny another tenant the same records.
-
WIDGET-001 — Availability-aware messenger and proactive messages. The messenger shows team availability from business-hour schedules (SLA-001) and live agent presence. When no human or permitted AI assistant is available it says so with the expected reply time, captures the visitor's email (or, where consented, SMS/WhatsApp under CHANNELS-001) so the answer reaches them, and creates the ticket instead of leaving the visitor waiting. Leads configure proactive messages triggered by page URL, time on page, scroll depth, exit intent, visitor attributes, returning visit or cart value, with audience, brand, frequency caps and quiet hours. Each proactive message shows a clear sender identity and an easy dismiss, respects consent and collector settings, and never starts a conversation that sends personal data on the visitor's behalf. Impressions, opens, dismissals and resulting conversations and resolutions are reported. This clause backs the homepage hero's "Before they ask".
Acceptance evidence: Outside configured hours, open the installed widget, see the offline message and expected reply time, leave an email and verify the ticket and the emailed answer. During hours with no agent online verify the same; with an available AI assistant verify it answers and discloses itself. Configure a proactive message on a checkout URL after 20 seconds with a once-per-day cap; verify it appears once, dismisses, stays silent under a declined collector setting and appears in reports with its impressions and conversations.
-
MAIL-001 — Complete support email. Connect inbound forwarding, an IMAP/SMTP mailbox, Gmail/Google Workspace or Microsoft 365/Outlook using scoped credentials/OAuth. New mail creates tickets and replies thread by stable Message-ID/In-Reply-To/References with deliberate handling of changed subject, aliases and multiple recipients. Operators manage CC/BCC, attachments, signatures and branded sender/reply addresses. Duplicate/redelivered mail, bounces, spam and auto-responders cannot create loops or send twice, and mail classified as spam or failing sender checks goes to the reviewable Suspended view of MAIL-002; reconnect/backfill has a visible cursor and errors, and removal stops new intake without deleting history.
Acceptance evidence: For each of forwarding, IMAP, Gmail and Microsoft 365, use the connection UI and real provider test accounts to receive a new thread, reply from the inbox, receive its follow-up and attachment, disconnect/reconnect with redelivery and observe bounce/permission failure. Verify no duplicate ticket/reply or machine-mail AI loop; keep provider-protocol tests separate from live acceptance. Spam and failing-sender mail reaches the MAIL-002 Suspended view, not a ticket.
-
MAIL-002 — Reviewable suspended and spam mail. Inbound mail that is spam-scored, fails DMARC/SPF/DKIM or alignment, comes from a blocked sender or domain, forges a verified customer's address, exceeds size limits or is a detected mail loop is never silently dropped. It lands in a Suspended view with its reason, authentication results, headers and safely previewed attachments, and creates no ticket, AI work, acknowledgment or notification. Permitted operators recover a false positive into a normal ticket that threads correctly (into the existing ticket when its references match) without retroactively triggering acknowledgments or AI unless they choose to; delete true spam; and block or allow a sender or domain. Recovery, deletion and list changes are audited. Suspended mail is kept for a stated retention period (default 14 days) and then explicitly deleted with an audit record; the view shows counts and the oldest age so nothing ages out unseen. Allow/block lists and suspension reasons are reportable.
Acceptance evidence: Through real inbound doors deliver a spam-scored message, a DMARC-failing message, mail from a blocked sender and a forged From of a known customer; verify each appears in Suspended with its reason and creates no ticket, AI request or outbound mail. Recover the DMARC-failing message into a new ticket and another into its existing thread, delete the spam, allow-list a sender and redeliver. Advance the clock past retention at the runtime edge and verify explicit, audited deletion; refuse every action to a role without permission.
-
OUTBOUND-001 — Agent-created and proactive tickets. From the inbox an operator creates a ticket for an existing or new contact: search by name, email or phone or create the contact inline under CUSTOMER-001 identity rules; choose brand, sender address, channel, form, fields, assignee and group; and make the first comment public or an internal note. A public first comment is sent as an outbound email, or, where the customer consented, as an approved SMS/WhatsApp template under CHANNELS-001. The customer is recorded as requester and the operator as submitter, and the customer's reply threads into the same ticket. Logging a phone call or walk-in creates a ticket without contacting the customer. Proactive service notices to several customers (for example a delayed order) create one ticket per requester with a preview, consent checks and rate limits, never send twice on retry and remain distinct from marketing campaigns, which belong to Mango.
Acceptance evidence: From the inbox create a ticket for an existing contact and one for a new contact, send the first public email, reply as each customer from a real mailbox and confirm the reply threads into the created ticket with requester and submitter attribution. Create an internal-only ticket (no send), a WhatsApp-template ticket to an opted-in number and one to an opted-out number (refused), and a proactive notice to three contacts with one failed send; verify no duplicate send on retry and refusal for an operator without create authority.
-
CHANNELS-001 — Messaging and social support. Connect US SMS through Twilio and WhatsApp Business, Instagram Direct and Facebook Messenger through authorized Meta business accounts. Inbound messages, supported media, delivery states and channel identity enter the shared inbox; replies return in the original channel. Respect consent, opt-out, A2P 10DLC registration, approved WhatsApp templates and channel reply windows; an expired window becomes an actionable blocker with an approved continuation, never silent loss or unauthorized cross-channel contact.
Acceptance evidence: Using each connected provider account, exchange a customer message/media and operator reply in one mapped conversation, redeliver a signed event, revoke the connection and exercise opt-out and expired-window/template refusal with visible delivery failure and no duplicate send.
-
CHANNELS-002 — B2B shared-channel support. Slack Connect and Microsoft Teams customer channels become authorized support intake, with thread replies, attachments, requester/account mapping and internal/private separation. The team can acknowledge, assign and hand off from Slack/Teams while the canonical support record retains the thread and current status. Installed-channel permissions, edited/deleted events, duplicates and disconnected channels have explicit behavior; Slack notifications alone do not satisfy this clause.
Acceptance evidence: Install scoped Slack and Teams apps, open support threads from allowed customer channels, reply and assign from both surfaces and observe bidirectional updates/reconnect. A private note, disallowed channel or revoked workspace must never leak into customer channels.
-
VOICE-001 — Telephone service and unified voice agent. Connect Aircall and Twilio Voice numbers for inbound/outbound customer support, business-hours routing, IVR, queues, transfers, voicemail and missed-call follow-up. Calls, consented recordings/transcripts and summaries attach to the customer conversation. The same governed AI procedures can serve voice, email and chat, with immediate human transfer and visible failed transfers; disclose automated agents and obtain recording consent under the configured US jurisdiction.
Acceptance evidence: Call a connected support number through IVR to an agent, transfer to a human, leave voicemail after hours and call back from the inbox; verify consent, transcript/recording access, linked history, failed-transfer escalation and erasure. Use the provider-approved emergency-calling test procedure to verify number/location routing and disclosed limitations before launch. Repeat an approved procedure across voice/chat/email and inspect one consistent authority policy.
-
QUEUE-001 — Assignment rules and available teams. Support leads define teams, membership, skills, capacity, availability and routing rules by channel, brand, language, account, tag or priority. Route to a named owner, team, round-robin or capacity-aware queue; explain which rule won, prevent starvation and preserve fair state across restarts. Manual takeover, absent/offline assignees, reassignment and unassigned overflow always leave a visible responsible queue.
Acceptance evidence: Configure two teams and a round-robin rule through settings, admit concurrent tickets through real channel routes, change availability and restart; verify ownership, fairness, overflow, explainable decisions and current-role refusal on manual takeover.
-
TRIAGE-001 — Intelligent triage. Each new ticket and customer message is classified for intent (from a lead-editable taxonomy with US commerce and SaaS defaults), sentiment and language, with a confidence score and the quoted evidence, by the configured model within AI-001 budgets. The predictions become ticket fields that QUEUE-001 routing, SLA-001 priority, AUTOMATION-001/002 conditions, views, AGENT-001 procedure selection and reports can use. A low-confidence prediction routes to the default queue instead of guessing. Operators correct a prediction and the correction is recorded as a label; leads see accuracy per intent against those labels before enabling a prediction for routing. With no model key there is no prediction, shown as unavailable and never invented.
Acceptance evidence: Enable triage and send messages with clear intents, negative sentiment and Spanish text through email and the widget; verify the fields, quoted evidence and confidence on each ticket, and that an intent routing rule and a negative-sentiment priority rule act. Send an ambiguous message (low confidence, default queue), correct a prediction and verify the accuracy report. Remove the model key and verify triage shows unavailable and routing still works.
-
QUEUE-002 — Structured and bulk queue work. Operators manage workspace-scoped tags, typed/validated custom issue fields (including values customers submit through FORMS-001) and priorities, and statuses from the STATUS-001 lifecycle; saved views can filter and sort on them. Leads select tickets and bulk assign, tag, change priority/status or apply a permitted MACRO-001 macro with a preview, per-record authority checks and a complete partial-failure result. Bulk actions cannot publish replies or reveal another workspace accidentally.
Acceptance evidence: Create a custom field and priority view, bulk-update mixed eligible/stale/forbidden tickets from the inbox and reload; verify each permitted effect, rejected reason, audit and lack of cross-tenant changes. Bulk-apply a macro and filter a view by STATUS-001 status and a form-submitted field.
-
QUEUE-003 — Collaboration without conflicting replies. Internal notes and @mentions notify only permitted teammates; followers (internal CCs, distinct from customer CCs and never shown to the customer) receive updates under NOTIFY-001; viewing, typing and unsent-draft indicators warn of collisions before send. Guarded send still refuses stale replies. Operators save personal/shared work views and reusable replies/macros with scoped permissions; private notes and drafts never appear in customer channels, forwarding or public history.
Acceptance evidence: Use two signed-in operators on the same ticket: type, mention, save a view/reply, race sends and reload. Confirm early collision warnings, one admitted final reply, scoped mention delivery and no private content in the visitor transcript. Add a follower and verify updates reach them and never the customer.
-
MACRO-001 — Action macros with placeholders. Operators apply a personal, group or shared macro that in one action sets the reply text (public or internal note), status, priority, tags (add or remove), assignee and group, followers, custom fields and attachments. Reply text supports placeholders for the requester's name, first name and email, ticket ID, subject and link, assignee, brand, organization, and custom ticket and contact fields, with explicit fallbacks (for example first name, else "there"). Applying a macro previews every change and puts the rendered text in the composer for editing; nothing is sent until the operator sends. A placeholder that cannot be resolved is flagged and blocks sending instead of reaching the customer as a literal. Macros are versioned, permission-scoped by role, group and brand, searchable, usage-reported and applicable in bulk (QUEUE-002). AI may recommend a macro but never applies one silently.
Acceptance evidence: From a ticket, apply a shared macro that sets status Pending, adds a tag, assigns a group and agent, sets a custom field and inserts a reply using the requester's first name and ticket ID; inspect the preview, edit the text, send and reload. Apply it to a requester with no name (fallback used) and with a placeholder for an absent custom field (flagged, send blocked). Verify a role without macro access cannot apply it, bulk application reports per-ticket results and the customer sees only the rendered text.
-
QUEUE-004 — Snooze and scheduled follow-up. Snooze a ticket until an exact timezone-aware time or a dependency; incoming customer replies wake it immediately. Schedule outbound service replies, see/cancel/edit them before send and prevent stale queued replies after a customer response or reassignment. Each follow-up has a responsible owner, due time, stop condition and visible pending/failed/uncertain outcome; restarts cannot lose it or resend an ambiguous attempt.
Acceptance evidence: From a ticket, snooze, schedule and cancel replies, then inject customer responses before/at the due time and restart the worker/executor. Observe a single wake/send or explicit refusal, overdue ownership and uncertainty without automatic replay.
-
STATUS-001 — Ticket status lifecycle. Every ticket has one status from a lifecycle the lead can extend: New, Open, Pending (waiting on the customer), On-hold (waiting on an internal team or third party), Solved and Closed, plus workspace custom statuses that each map to one of those categories. A customer reply to a Pending or On-hold ticket returns it to Open and wakes its owner. On-hold and every internal status label are never shown to the customer, who sees an open request in the widget, portal and email. A customer reply to a Solved ticket reopens it. After a lead-configured period (default 4 days) a durable time-based automation (AUTOMATION-002) moves Solved to Closed, and Closed is final: a customer reply to a Closed ticket creates a new follow-up ticket linked to it that carries the requester, CCs, tags and fields. Status filters, sorts, views, bulk edits (QUEUE-002), SLA pausing (SLA-001), resolution cycles (OUTCOMES-001) and reports all use this lifecycle, and every change records its actor, time and source (person, rule, automation or customer reply).
Acceptance evidence: Through the inbox, widget and email routes, move a ticket through New, Open and Pending, reply as the customer and observe Open with an owner wake. Set On-hold and read the widget, portal and email views for absence of the internal state. Solve it, reply as the customer and observe reopen; solve again, advance the clock at the runtime edge past the close period and observe Closed by automation; reply to the Closed ticket and observe a new linked follow-up ticket with the carried fields. Create a custom status in the Pending category and confirm SLA pausing and report attribution; refuse a status change by a forbidden role.
-
SLA-001 — Business-hour service commitments. Leads configure first/next response and resolution SLAs by priority, customer plan, channel and brand, using US IANA timezones, weekly hours and holiday calendars. Show due times and pause reasons in the queue; Pending pauses customer-wait clocks and On-hold follows the policy's stated choice under the STATUS-001 lifecycle, and reopen restarts the next-response clock. Durable approaching-breach, breach and unattended-ticket alerts escalate to named backups through inbox/email/Slack/Teams and persist until acknowledged or resolved.
Acceptance evidence: Configure two calendars and policies through settings; admit/reply/pause/reopen tickets across a holiday and DST boundary, restart and advance the test clock at the network/runtime edge. Compare displayed due times and breach/workload reports to hand calculations and confirm escalation/acknowledgment and no duplicate alerts. Verify Pending pauses and On-hold follows the configured policy.
-
AUTOMATION-001 — Explainable durable support workflows. Leads version event-triggered condition/action rules (on ticket create and update) for routing, tagging, priority/status, reminders, customer updates and refund-exception escalation; actions include notifying the requester and CCs, the assignee, the group or followers (NOTIFY-001), adding an internal note and calling a signed webhook. Time-based conditions are AUTOMATION-002. Preview the effect against historical tickets in a workflow sandbox without real sends, then publish explicitly. Ordered/conflicting rules, loop prevention, owner, due time and stop condition are inspectable. Background execution persists decisions and failure/uncertainty across handoffs and restart; operators pause, cancel or reconcile work without blind retries.
Acceptance evidence: Configure and simulate a route/tag/status/reminder rule through workflow settings; prove sandbox sends no external effects. Publish it, create matching/nonmatching tickets, cause a provider failure and process restart, inspect the chosen rule and terminal result and pause it before another side effect. Include a notify-assignee and a customer-update action and verify one send to the permitted recipient only.
-
AUTOMATION-002 — Time-based automations. Leads define automations that run at least hourly over New, Open, Pending, On-hold and Solved tickets. Conditions include hours since created, updated, assigned, requester update, agent update, Pending, On-hold, Solved and SLA due, in calendar or business hours (SLA-001 schedules), combined with status, priority, tag, form, field, brand, channel and group. Actions set status, priority, tags, fields and assignee or group, add an internal note and send a templated customer or teammate notification (NOTIFY-001). An automation must include a condition its own action nullifies, or it fires at most once per ticket, so it cannot repeat; publishing one that could loop is refused. Runs are durable across restart, never replay an uncertain send, and record which automation changed what. Ready templates cover the common cases: nudge the customer after 48 business hours in Pending, auto-solve after 96, and close Solved after N days.
Acceptance evidence: Through workflow settings create the Pending nudge at 48 hours and auto-solve at 96 hours and a Solved-to-Closed automation; preview them against current tickets with no side effects. Seed tickets at known times, advance the clock at the runtime edge across an hourly boundary, a weekend and a DST change, and restart mid-run. Verify exactly one nudge per ticket, auto-solve at the configured business time, no action after a customer reply resets the condition, refusal to publish a repeating automation and "automation <name>" recorded as the actor of each change.
-
NOTIFY-001 — Customer acknowledgments and teammate notifications. Default, editable triggers send the requester and CCs one "request received" acknowledgment for a new ticket (per channel and brand, with the ticket reference and expected reply time), a notification when a public reply is added, and a solved notice. Machine-generated mail, suspended mail (MAIL-002), imports and merges never trigger them, and each ticket receives at most one acknowledgment even under redelivery. Teammates are notified by inbox, email, push (MOBILE-001) and Slack/Teams: the assignee on assignment and on customer update, the group on unassigned group tickets, followers on update and mentioned teammates on mention, each according to personal preferences and current permission to the ticket, workspace and brand. Templates use MACRO-001 placeholders with a visible failure for a missing value. Every notification carries loop-suppression headers and records its delivery outcome; an uncertain send is never replayed.
Acceptance evidence: Create tickets through email, the widget and a request form with a CC, redeliver the same inbound message and send an auto-responder; verify exactly one acknowledgment to the requester and the CC and none for the auto-responder, an import or a merge. Assign the ticket, add a follower, update it as the customer and mention a teammate; verify each notification reaches only permitted current members according to preference, a revoked member receives nothing, a group notification reaches the group and an uncertain provider send stays uncertain without a second send.
-
CONVERSATION-002 — Merge and external forwarding. Merge duplicate tickets with an explicit surviving thread, source links, attribution, attachments, notes, SLA/outcome treatment and reversible history where safe. Forward selected customer-visible content to an external partner and thread their reply back while clearly distinguishing an external participant from a teammate. Customer identity, private notes and channel restrictions are previewed; merges cannot cross tenants or silently erase evidence.
Acceptance evidence: Merge two duplicate tickets via the inbox, inspect both source histories and reports, then forward selected content to a partner and receive their reply. Verify no private note leaks, no duplicate customer send, explicit unsafe-undo refusal and no cross-workspace merge.
-
CONVERSATION-003 — Problem and incident linking. An operator marks a ticket as a Problem and links Incident tickets that report the same issue, manually, from search or from a TRIAGE-001 or agent suggestion a person confirms. The problem lists its incidents with customers and counts. Solving the problem can, with a previewed public reply that uses MACRO-001 placeholders per requester, solve or update every linked incident in its own channel, each reply going only to that incident's requester, with per-ticket outcomes and consent and reply-window checks. Incidents keep their own SLA, history and CSAT; unlinking is audited. A problem can link an ESCALATION-001 engineering issue so that one shipped fix updates every affected customer.
Acceptance evidence: Create a problem and link five incidents arriving by email, widget and SMS; solve the problem with a previewed bulk update and verify each requester receives only their own reply in their channel, an incident whose reply window expired is reported blocked, no customer sees another's identity and each incident keeps its own status, SLA and CSAT invitation. Unlink one incident before solving and verify it is untouched.
-
CUSTOMER-001 — Customer and company support records. Maintain contacts, verified linked channel identities, companies/accounts, account members, custom attributes, consent/preferences and all interaction history. Link/unlink or merge identities with preview and source provenance; email text alone never grants access. Show current business-system context with last sync time, permission and unavailable/stale state, plus account-level open work and relationship history. Import contacts and companies from CSV outside a vendor migration with column mapping, validation, duplicate matching by email or external ID, a dry-run preview and whole-import undo; such imports send nothing.
Acceptance evidence: Open one customer arriving over chat/email/social, explicitly link their verified identities and company, inspect account tickets and edit attributes; attempt an unauthorized identity merge, deny another account history and show stale connector context after disconnect. Import a contacts-and-companies CSV with a duplicate and an invalid row; preview, apply and undo with no send.
-
COMMERCE-001 — Shopify order actions. Connect Shopify stores with merchant-granted scopes; show customer orders, fulfillment, delivery, return and refund state in the conversation. Authorized agents/humans can perform permitted return, cancellation and full/partial refund actions with USD amounts, tax/shipping implications and a reason. Preview the exact order/action, require the configured approval and limit, use provider idempotency and verify provider state before telling the customer it succeeded.
Acceptance evidence: Connect a Shopify test store through settings, find a customer order from a ticket, approve a bounded partial refund/return or cancellation and read back the order/provider ledger. Deny excess/refused/revoked scopes, double clicks and cross-store access; a timeout remains pending/uncertain until reconciliation, with no second refund.
-
BILLING-001 — Stripe billing and subscription resolution. Connect Stripe for customer/payment/invoice/subscription context and permitted refunds, credits and subscription cancellation, pause or plan changes. Show USD totals, tax/proration/effective-date consequences and linked provider records before approval; separate read, prepare, approve and execute scopes and spending limits. Reconcile actual provider state after timeout and report what changed in the original conversation. No raw card data or customer funds enter HappyToHelp.
Acceptance evidence: From a support ticket linked to a Stripe test customer, inspect an invoice, approve a bounded refund and a subscription change and verify provider readback plus customer-visible results. Exercise duplicate requests, proration preview, denied approval and an uncertain timeout without double money movement.
-
CRM-001 — Live CRM and account context. Connect Orbit, HubSpot and Salesforce independently; map contacts, companies/accounts, support entitlements, plan and owner to support records with source IDs and sync freshness. Read relevant CRM context and write only explicitly scoped support outcomes/approved field changes. Conflicts, identity mismatch and revoked grants are surfaced; the CRM remains the sales/account system of record.
Acceptance evidence: For each named CRM, connect a test account through settings, map a customer, change source entitlement and refresh the ticket, publish an approved support outcome and disconnect. Verify conflict handling, read-only scope refusal and no cross-account data exposure.
-
ESCALATION-001 — Engineering and team escalations that return. Create or link GitHub Issues, Linear and Jira issues and Slack/Teams handoffs from a conversation, choosing exactly what context/attachments to share. Persist reciprocal links, assignee, status and dependency; signed provider updates return to the support thread, wake its owner and draft a customer update when a fix ships. Issue closure alone never proves customer recovery; operators approve customer publication or grant an explicit bounded policy.
Acceptance evidence: From a ticket, create/link an issue in each named tracker and a Slack/Teams handoff; receive duplicate/out-of-order provider status updates and close the issue. Verify one linked escalation, refreshed ticket state, private-content exclusion and an approved customer update with recovery still unconfirmed until observed.
-
API-001 — Owned API and managed connectors. Expose a documented versioned HappyToHelp API and signed outbound webhooks for conversations, contacts, articles and support events with scoped authorization, pagination, stable cursors, idempotency and revocation. Provide Zapier actions/triggers and managed MCP tools with the same tenant/action boundaries. Offer Help Scout Inbox API/webhook read synchronization for staged migration/coexistence, with cursors and deduplication; it is separate from native API authority. Connection health, scopes, event attempts and manual reconciliation are visible. Creating and appending support requests from another product or agent with credentials bound to a source product is API-002.
Acceptance evidence: Use a scoped client to page/export records and perform native guarded writes, validate a signed webhook and revoke the token. Exercise a Zapier trigger/action, MCP read versus denied write and Help Scout incremental ingestion with duplicate events/reconnect; verify no replay of old imports or erased identities.
-
API-002 — Create and append support requests from another product or agent. A workspace owner/admin issues a named machine credential for one source product or agent (for example a handoff from Handset) and binds it to exactly what it may touch; the scoped workspace API then lets that product create a ticket and append to it without a human session. Credentials are extensions of the CONNECTIONS-001 token model, not a second system: bearer-only, no cookies, no CORS, secret shown once at issue and stored only as a hash, with a non-secret display prefix, name, source-product label and the issuing member, creation time, optional expiry (UTC), last-used time and last-used source visible in Settings. Issue, rotate and revoke require the current owner/admin with step-up; rotation issues a new secret and keeps the old one valid for an owner-chosen overlap (default none, maximum 7 days) before it retires, and revocation, expiry, a blocked or deleted workspace and a restore take effect on the next request, with an in-flight create either committed whole or refused with nothing stored. Scopes are separate and narrow:
conversations:create,conversations:read(bound by default to the conversations the credential created),messages:append(customer-side message or internal note on a conversation inside its bounds) and, unchanged, the existing operator-stylemessages:write; a read-only, a create-only and an append-only credential can each be issued, and no scope implies another. Bindings limit the credential to named brands, mailboxes/sender addresses, groups, request forms and an API channel label (api:<source product>, a first-class channel in inbox filters, reports, SLA and triage); it may set only priority levels and existing workspace tags its bindings allow (an unknown tag is refused, never created), may not assign, choose status beyond New, write internal-only fields or act as an operator, and an operation outside its bounds returns 404 for another resource and 403outside_credential_boundsfor a disallowed value, never a silent adjustment. Create takes a requester identified by email, E.164 phone or the caller's own external ID (namespaced to its source product) with optional name; subject, plain-text body and attachments passed by reference (a prior bounded upload id or a public HTTPS URL fetched under the existing egress rules with a required SHA-256, no redirects, size and 10-second bounds and the widget's type rules, the whole request atomic so one bad attachment stores no ticket); source channel label, priority and tags; and a source-product reference{product, ref, url}where the product label is fixed by the credential and cannot be spoofed, the URL is HTTPS without embedded credentials and is shown to operators as a back-link ("Created via Handset, open in Handset") and never fetched, and a second create for the same source reference under a different key returns 409source_ref_existswith the existing ticket ID so the caller appends instead. TheIdempotency-Keyheader is required on create (1-200 characters, scoped to workspace and source product so a rotated or reissued credential still deduplicates, retained at least 30 days): the same key and canonical body return the original status and body marked as a replay, a different body returns 409idempotency_conflict, and a key still in flight returns 409in_progresswithRetry-After; append is idempotent by the existinglocalId. The identity rule is CUSTOMER-001's: a requester matches an existing contact only by an exact verified key, a new contact created by the credential is marked as asserted by that credential and unverified, email or name text alone never grants history access or merges contacts, two identifiers that point at different contacts return 409identity_conflictwithout disclosing either contact, a requester matching an erasure tombstone is refused withidentity_erased, and responses have the same shape whether or not the contact already existed. Append posts a message to an existing conversation as the requester (kindcustomer) or as an internal note (kindnote), never as an operator or as AI; acustomermessage reopens a Solved ticket and creates the linked follow-up of a Closed one under STATUS-001, a merged ticket answers 409merged_intowith the surviving ID, and attachments follow the same reference rule. API-created tickets are untrusted customer content: they pass the same triage, automations, routing and AI-agent rules as any new ticket with sourceapi, and body text, subject and source fields can never instruct the agent or open an external effect. They respect spam, abuse and consent: blocked senders, blocked identities and per-requester create caps (default 5 per hour, owner-configurable) place the request in Suspended under MAIL-002 with a reason and a 202held_for_reviewresponse and no ticket-created event, AI request or outbound message; acknowledgments and any customer-facing send follow NOTIFY-001 and CHANNELS-001, an email acknowledgment is sent only when the caller supplies a consent record (channel, basis, time) the workspace accepts for that source, an SMS or WhatsApp send needs recorded opt-in and an approved template and an opted-out number is refused while the ticket is still created, and a created ticket otherwise contacts nobody. Signed webhooks use the existingintegrations.webhook.v1signing, delivery and retry policy and addconversation.status_changed(ticket ID, previous and new status category and ID, source reference) andconversation.assigned; a destination can be limited to tickets created by one credential or one source product, and events keep carrying identifiers and values, never transcript text, email addresses or phone numbers. Limits are explicit: the existing per-credential requests-per-minute limit plus a separate create quota per minute and per day configured on the credential under workspace and installation ceilings, and the per-requester cap, each refused with 429,Retry-After,RateLimit-Limit/Remaining/Resetheaders and a machine-readable code naming which limit (credential,requesterorworkspace); oversize bodies return 413payload_too_largeand unsupported types 415, nothing is silently truncated or dropped, and storage or plan exhaustion returns 503unavailablewithRetry-Afterand no partial ticket. Errors use the existing{error:{code,message}}shape with stable codes. Every action is audited under AUDIT-001 with a machine actor named on the credential: issue, rotation, scope or binding change, first use, expiry, revocation and denied attempts (counted per credential and window, not one event per probe), and every create or append records the credential name, source product and reference, request ID, idempotency-key digest and outcome in ticket history ("Created by API credential Handset support handoff"), never presented to the customer as a person, and the credential's name survives its revocation while an erased issuer is redacted without losing the event. Erasure under ERASURE-001 removes personal content from API-created tickets, stored replay bodies, pending event payloads and attachment bytes, keeps an opaque tombstone and the source reference without personal data, and fences a stale replay or a later create from resurrecting the identity. Portability under PORTABILITY-001 exports API-created tickets with channel label, source reference and machine-actor name, and exports credential metadata (ID, name, source product, scopes, bindings, creation, expiry, revocation, last-used) without hash or secret; restore creates every credential revoked and inert so the receiving owner must reissue, carries idempotency records as key and body digests only, and replays nothing. Documentation (docs/api.md) lists the new operations, scopes, bindings and error codes with runnable examples that keep tokens out of command arguments.Acceptance evidence: Through the documented bearer API and Settings, and with receivers and clocks faked only at the network edge: (1) issue a create-only, an append-only, a read-only and a full credential, observe each secret once, confirm the stored value is a hash and Settings shows prefix, source product, scopes, bindings, expiry and last used; (2) create a ticket with a valid key, then replay the same key and body for the same status and body marked as a replay and exactly one ticket, send the same key with a changed body for 409
idempotency_conflict, fire two concurrent creates with one key for one ticket and onein_progress, and omit the key for 400; (3) create with email, with phone and with an external ID, once for an existing verified contact (history not exposed, no merge), once for a new contact (marked asserted and unverified) and once with two identifiers on different contacts (409identity_conflict, neither disclosed), and one for an erased contact (identity_erased, no identity recreated); (4) verify the operator sees subject, body, attachments, API channel label, priority, tags, requester, the credential as machine actor and a working source back-link, that a spoofed source product is refused, that a second create with the same source reference returns 409source_ref_existswith the existing ID, and that an unknown tag, an assignment attempt and an internal field are each refused; (5) attach a bounded upload, a digest-matching HTTPS URL, a mismatching digest, a redirecting URL, a private-address URL and an oversize file and verify the atomic result (one stored ticket with bytes intact, or none) and 413/415 with no truncation; (6) append a customer message and an internal note to the created ticket, to a Solved one (reopens), a Closed one (new linked follow-up) and a merged one (merged_into), and refuse an append by a create-only credential, to another credential's conversation and across workspaces with 404; (7) bind a credential to one mailbox and brand and prove a create for another mailbox or brand is refused withoutside_credential_boundsand not adjusted; (8) deliver a blocked sender, a requester over the per-requester cap and a message failing abuse checks and verify 202held_for_reviewin Suspended with a reason and no ticket-created event, AI request or outbound mail, then release one from Suspended; (9) send an acknowledgment request with and without a consent record, an opted-in and an opted-out SMS/WhatsApp requester and verify consent, template and opt-out rules and a created ticket either way with no duplicate send on retry; (10) exceed the per-minute limit, the create quota and the per-requester cap and verify 429,Retry-After, the rate-limit headers and the limit-naming code each time, with no partial ticket; (11) receive signedconversation.created,message.created,conversation.status_changedandconversation.assignedat a destination limited to one credential, verify the signature, no transcript text or contact data, duplicate/out-of-order handling and a 429 retry with the same ID, and that another credential's tickets send nothing; (12) rotate a credential with an overlap, use old and new secrets in the window, then see the old refused after it, then revoke, expire (advance the clock) and block the workspace and verify 401 on the next request and an in-flight create committed whole or absent; (13) open the audit export and ticket history to find issue, rotate, binding change, first use, denial counts, revoke, every create and append with credential name, source product, reference and request ID and no secret, and erase the issuing member and a requester to verify redaction without losing the events; (14) erase a populated API-created contact and verify ticket content, stored replay bodies, pending event payloads and attachment bytes are removed, the tombstone and fences hold against a stale replay and a new create, and the owner-visible counts are complete; (15) export and restore into a clean installation and verify tickets with channel label, source reference and machine-actor name, credentials present as metadata only (no hash or secret), every credential revoked and unusable, idempotency digests carried, erasure fences kept and nothing replayed; (16) run thedocs/api.mdexamples against a dev server and confirm they pass and expose no secret in arguments or logs. -
MOVE-IN-002 — Switch from every named incumbent. Provide guided one-click connection or export upload for Zendesk, Intercom, Help Scout and Freshdesk, covering contacts/companies, conversations/messages/attachments/private notes, tags/custom fields, ownership, timestamps and articles/categories/publication. Preview supported mappings and every unsupported field/rule/brand/permission; no silent truncation. Resume with source IDs, deduplicate a second run, perform an inert final delta cutover and explicitly repoint channels. Preserve links and counts; imports never activate automations or expose formerly private knowledge. Imported tickets keep their email threading keys so post-cutover replies land in them (MOVE-IN-003), and configuration moves in under MOVE-IN-004.
Acceptance evidence: For each of the four vendors, use its documented export/API through Move in with representative realistic records, compare exact source/target counts and attachment bytes, inspect omission reports, resume/repeat/undo and final delta, then receive a new live message after channel cutover. Exercise role revocation and source redaction without accidental sends. Reply to a pre-cutover notification (MOVE-IN-003) and import configuration (MOVE-IN-004).
-
MOVE-IN-003 — Replies to pre-migration mail land in the imported ticket. Imported tickets keep their email threading keys: every source Message-ID and In-Reply-To/References chain, the source ticket number and each vendor's reply token (Zendesk encoded IDs in
[XXXX-XXXX]brackets and ticket-number subject tags, Help Scout conversation numbers and reply addresses, Freshdesk[#ticket]subjects and reply-to addresses, Intercom conversation reply addresses). After channel cutover, a customer reply to a notification the old system sent is matched by those keys in that priority and lands in the imported conversation with its migrated requester, owner, group and status, reopening it under STATUS-001 when Solved and creating a linked follow-up when Closed. A key that matches more than one record, or a record belonging to a different customer identity, goes to review instead of the wrong ticket; an unmatched reply creates a new ticket marked as a possible pre-migration reply. Keys are imported inertly and are covered by repeat/undo equality and erasure.Acceptance evidence: Import Zendesk, Help Scout, Freshdesk and Intercom datasets that carry real notification headers, perform cutover, then reply to a pre-cutover notification from each vendor by headers only, by subject token only and by reply address; verify each reply lands in the right imported conversation with its owner and status, reopens a Solved one and links a follow-up to a Closed one. Send a reply whose token belongs to another customer (held for review) and an unmatched reply (new ticket with the hint); undo the import and verify the keys no longer match.
-
MOVE-IN-004 — Bring configuration, not only history. Move in maps each incumbent's configuration into native equivalents: macros with their actions and placeholders (MACRO-001), views, groups and memberships, business-hour schedules and holidays, SLA policies, request forms and custom fields (FORMS-001), triggers and automations, brands and help-center structure. A per-item preview shows what translates exactly, what translates with a stated change and what is unsupported, with the reason. Translated rules arrive inactive as drafts; an admin reviews, simulates them in the AUTOMATION-001 sandbox and activates them, and nothing sends, routes or breaches during import. Placeholders translate to native placeholders or are flagged.
Acceptance evidence: Import a Zendesk configuration with a macro that uses placeholders and four actions, a view, two groups, a schedule with holidays, an SLA policy, two request forms and a trigger/automation pair, plus the Help Scout, Freshdesk and Intercom equivalents. Inspect the per-item mapping, activate selected items after simulation and verify they behave as the source did on a test ticket; unsupported items are listed and inactive drafts cause no effect.
-
PORTAL-001 — Authenticated customer self-service. A customer securely signs in to a branded portal to search permitted knowledge, create tickets with attachments through FORMS-001 request forms (which anonymous visitors may also submit where the lead allows), review/reply/reopen their own requests and manage notification preferences. Company-wide ticket visibility is an explicit entitlement, never inferred from an email domain. Identity recovery, revoked membership and inaccessible/deleted requests fail safely across web and mobile.
Acceptance evidence: As two customer identities in different companies, sign in, create/reply/reopen a ticket and inspect its history; grant then revoke company visibility, recover identity and verify all unauthorized deep links and attachments are denied. Submit an anonymous request form and a signed-in one (FORMS-001).
-
FORMS-001 — Customer request forms with custom fields. Leads build several request forms (for example Order problem, Refund, Technical) from typed custom ticket fields (text, number, decimal, date, drop-down, multi-select, checkbox, pattern-validated text and lookups to an order or account), with required and conditional fields, customer-facing labels, descriptions and locale translations, and offer them in the help center, portal, widget and API. Anonymous visitors may submit where the lead allows, with email verification, rate limits and bot protection; signed-in customers' identity and organization are prefilled. Submissions are validated on the server and refused with the failing field named; accepted values are stored as typed ticket fields with the chosen form and are usable by QUEUE-001 routing, SLA-001 policies, AUTOMATION-001/002 conditions, views and reports. Agents see and edit the same fields under field-level permissions; forms and fields are versioned so old tickets keep their values.
Acceptance evidence: Submit the Order-problem form anonymously (with email verification) and the Technical form signed in, each with a required field and a conditional field shown only for a chosen value; confirm both tickets arrive with typed values that a routing rule and an SLA policy act on. Submit invalid input (a missing required value, a pattern failure and a hidden conditional value injected through the API) and verify server refusal naming the field. Translate a form and submit it in Spanish; deny an agent role a restricted field.
-
KNOWLEDGE-002 — Governed private and multilingual knowledge. Support public and authenticated private help centers, multiple languages/locales, version history, editorial review, redirects and brand/domain publishing. Source refreshes and translated drafts preserve permissions and previous published versions; restricted knowledge is never exposed to public search, an unauthorized agent answer or another account. Agents may propose cited changes, while named editors control publication.
Acceptance evidence: Publish an English article and reviewed translation, restrict a collection by explicit account/company entitlement (email-domain membership alone does not establish that entitlement), update/rollback a version and follow an old URL. Search and ask the agent as public, permitted and forbidden customers and verify permission-aware citations, locale fallback disclosure and failed-refresh preservation.
-
KNOWLEDGE-003 — Branded help center, article feedback and knowledge in the ticket. Leads brand each help center with logo, colors, fonts, custom domain, navigation and editable page templates (home, category, section, article, search and request form), previewed before publication with readable contrast enforced. Each article offers "Was this helpful?" votes with an optional comment. Leads see per-article views and votes, search terms with and without results, click-through and tickets created after reading, by brand and locale. From a ticket an operator searches the help center, previews an article and inserts its link or text into the reply in one action, limited to knowledge that customer may see, and can flag an article as outdated or propose a new one (PUSH-004).
Acceptance evidence: Brand two help centers with logo, colors and domain and edit an article template; preview, publish and verify an unreadable color is refused. Vote on an article as a visitor, search for a term with no results and then open a ticket; compare analytics with the known events. From a ticket search, insert an article link and send; verify a restricted article cannot be inserted into a reply to a customer without access.
-
BRANDS-001 — Multi-brand support operations. A business can manage distinct brands, mailboxes, widget identities, domains, help centers, signatures, channels and policies with deliberate shared teams and reporting. Route and report by brand without mixing customer identities, private knowledge or sender credentials. Cross-brand administration and customer handoffs require explicit access and a visible explanation.
Acceptance evidence: Configure two brands with different domains/senders and a shared permitted team; receive and resolve messages from each, change one policy, inspect per-brand and aggregate reports and deny an unauthorized cross-brand customer/agent read.
-
ACCESS-001 — Enterprise identity and custom permissions. Retain native owner/password access while optionally connecting Google Workspace, Microsoft Entra ID or Okta using SAML/OIDC SSO and SCIM provisioning. Define custom roles and field/tool/brand/team permissions for operators, admins, reviewers and agents; separate integration installation, refund approval, knowledge publication and destructive access. Collaborator (light-agent) seats can view permitted tickets, add internal notes and follow tickets but cannot reply publicly, change fields or read restricted knowledge. Deprovisioning/revocation promptly ends sessions, pending tool authority and customer-data access, with tested owner recovery. RULED interim default and target (ct, 23 October 2026 10:46Z):
knowledge.editgates internal knowledge management and connected-application article reads;knowledge.publishstill gates publication. Published help keeps its audience gates, so a reader never gains internal articles through it. A separate knowledge-read permission is required for read-only access to selected internal knowledge without edit or publish authority.Acceptance evidence: Provision an operator through each supported identity protocol, assign a restricted custom role, attempt denied exports/refunds/publication, then deprovision during active work and verify sessions/tools lose access. Native owner recovery remains usable and cannot be replaced by provider configuration. A collaborator seat adds a note and is refused a public reply. UNPROVED acceptance target: Exercise the interim
knowledge.editgate on internal management and connected-application article reads, and retain published-help audience denials. UNPROVED acceptance target: For the separate knowledge-read permission, prove a custom role with read only reads selected internal knowledge, cannot edit or publish, loses access on the next request after revocation, and has audited access, refusals and revocation. -
IDENTITY-003 — Two-factor authentication for native accounts. Native password accounts enroll a second factor: a TOTP authenticator app or WebAuthn security keys and passkeys, with ten single-use recovery codes shown once. An owner can require two-factor sign-in for every teammate or by role; affected users must enroll at their next sign-in before reaching any data, and existing sessions without the factor end. A sign-in without the factor, with a wrong or replayed TOTP code (one use per time step) or with a used recovery code is refused, rate-limited and audited. Owner-assisted reset of a teammate's factor requires the owner's own recent factor, notifies the teammate and is audited; an owner who loses every factor recovers through the documented installation-level owner recovery through
rer, never by email alone. Refund and billing approval (COMMERCE-001, BILLING-001), integration and credential installation, exports, erasure, role changes and the two-factor policy itself require a recent second-factor step-up. API access uses scoped tokens (CONNECTIONS-001), never a password alone. SSO users follow their identity provider's MFA (ACCESS-001). This adds to the retained native password identity (IDENTITY-002) and never replaces it.Acceptance evidence: As owner require two-factor sign-in; sign in as an agent and be forced to enroll TOTP and receive recovery codes; sign out and verify refusal without the factor, with a wrong code, with a reused code and with a used recovery code; sign in with a passkey. Reset the agent's factor as owner with a step-up and observe the notification and audit. Approve a test refund and start an export with and without a recent step-up; recover a locked-out owner through
rer; verify sessions without the factor ended when the policy was turned on. -
MOBILE-001 — Support from a phone. Provide responsive operator/customer web flows and native iOS/Android operator apps for shared queues, push notifications, assignment, notes, attachments, knowledge, approval and reply. Show offline state and protect cached customer data; drafts may persist safely, but reconnect must revalidate role/frontier and scheduled effects. Deep links return to the correct permitted workspace and push payloads omit sensitive content by default.
Acceptance evidence: At 1440 and 390 use realistic end-to-end web tickets; on iOS and Android receive a push, deep-link, assign/note/reply with attachment, go offline, lose authority and reconnect. Verify no stale duplicate send, leaked push content or retained cache after sign-out/revocation.
-
OUTCOMES-002 — CSAT across support channels. Offer configurable post-resolution satisfaction surveys via widget, portal, email and permitted messaging channels with rating scale, optional comment, locale, send timing and opt-out. Associate one latest response with the exact resolution cycle and channel; preserve previous-cycle history and reconcile signed response links without requiring a widget session. Leads inspect low-score follow-up and customer recovery without auto-closing complaints.
Acceptance evidence: Resolve tickets across the channels, receive/answer a survey as the eligible customer, rerate, reopen and revoke/expire a response link; compare cycle-level CSAT and opt-out behavior, ensure no duplicate invitation and verify erased comments disappear everywhere.
-
REPORTS-002 — Workload, service and agent outcomes. Leads explore team/agent workload, backlog age, incoming volume, response/resolution time, SLA compliance, reopened requests, CSAT and AI containment/handoff/resolution by channel, brand, account, tag and procedure version. Publish inspectable numerators, denominators, timezone and exclusion rules; distinguish bot closure from verified resolution and include failures/unknowns. Operators record time spent per ticket (a timer while the ticket is open, with manual adjustment) and leads report handle time by agent, form and intent. Export complete formula-safe records and schedule permission-scoped reports; no sampling or silent truncation.
Acceptance evidence: Build a known multichannel cohort containing reassignment, reopen, AI handoff, SLA breach and imported history through public routes. Compare dashboard drill-downs, workload and scheduled CSV delivery to hand-calculated totals; revoke a recipient and verify private data is withheld. Record and adjust handle time on tickets and compare handle-time totals.
-
AGENT-001 — A production support agent with clean handoff. The AI agent answers using approved help-center content, permitted past conversations and fresh connected customer/product state, with citations, retrieval permissions and clear AI disclosure across chat/email/voice. Execute only enabled procedures/tools; distinguish advice, prepared action, approved execution and observed success. A customer can request a person; uncertain, low-evidence or disallowed actions transfer promptly with transcript, sources, attempted actions, failures and the next responsible human. The agent stops replying after handoff until explicitly resumed.
Acceptance evidence: On representative real-provider channel journeys, ask grounded and unanswerable questions, attempt restricted retrieval/actions, request a human mid-tool-call and disconnect. Verify cited valid answers, no private leakage, no unauthorized tool call, durable handoff context and no competing post-handoff AI answer; record live evaluation separately from fixtures.
-
PROCEDURE-001 — Natural-language procedures and release simulation. Support leads author versioned natural-language operating procedures tied to intents, knowledge versions, live data requirements, tools, approval gates, budgets and human escalation. Simulate paths, adversarial cases, provider errors, handoffs and permissions against redacted historical examples in an isolated workflow sandbox with no real actions. Per-procedure evaluations must pass declared outcomes before an authorized staged release; compare versions, stop/rollback a rollout and keep old cases reproducible.
Acceptance evidence: Through procedure settings, draft a refund procedure, simulate allowed/denied/timeout/prompt-injection paths with network-edge fakes, inspect a failing case and prevent release. Approve a passing version into a bounded live cohort, revoke a tool and roll back; verify no sandbox external effect and exact version linkage in conversations.
-
AGENT-002 — Inspectable quality and resolution economics. Operators inspect a redacted per-conversation/tool-call trace with source/version, requested scope, human approval, timings, provider outcome and verified result. Leads explore procedure-level evaluation coverage, resolution/reopen/handoff rates, failure clusters and provider costs/usage without treating attempted actions as success. Human labels and later customer outcomes can correct attribution; provider usage remains accounting evidence, not a customer balance or invented monetary saving.
Acceptance evidence: Open production-run traces from a conversation and drill from a procedure report to supporting cases; include timeout, denied tool, handoff, negative CSAT and reopened outcomes. Compare rates and USD provider-cost estimates to raw usage and known denominators, redact secrets and show unavailable price data explicitly.
-
FEEDBACK-001 — Source-linked feedback and release follow-up. Capture product feedback from a support conversation with the customer/account and supporting quote, link or create its request in Penny, and link engineering delivery in Vector or the buyer's issue tracker. Subscribe the affected requester to an approved service update when a linked feature/fix ships, respecting preference, channel policy and unresolved recovery. Penny owns aggregation, prioritization, roadmap/changelog and requester closure; HappyToHelp retains the support history and responsibility for the customer response.
Acceptance evidence: From two related customer tickets, hand off source-linked feedback to Penny, associate an engineering issue and receive a release event; preview and approve requester updates, deduplicate events, honor opt-out and keep a still-failing customer request open.
-
ERASURE-001 — Customer erasure with coherent history. Owner/admin contact erasure removes personal content from native/imported transcripts, notes, context, feedback, stored files and archive copies while retaining nonpersonal identity/frontier and an opaque erasure tombstone. Erasure fences APIs, pending events, source re-import and stale restore from resurrecting the identity. Provide completion/failed counts for all stores and separately request deletion from connected providers under their capabilities; do not claim already sent messages or offline archive bytes were recalled.
Acceptance evidence: Erase a populated native/imported contact through the authorized owner route, inspect D1/R2 and the resulting export, retry a stale API/import and test role/cross-tenant denial. Verify coherent redacted threads, tombstone fencing and explicit unresolved external/old-archive deletion.
-
AUDIT-001 — Security and accountable actions. Encrypt configured provider credentials under installation custody, never return secrets in ordinary reads/logs/exports and enforce tenant, role, origin and public rate limits at every door. Keep an inspectable, exportable append-only audit of authentication/permission changes, imports/exports/erasure, assignments, procedure changes, approvals and external actions with actor, purpose, source, time and outcome; redact erased actors without losing the event. Configure retention/legal holds with visible effects and never silently delete evidence to improve reports.
Acceptance evidence: Using owner/security views, rotate/revoke credentials, attempt cross-tenant/CSRF/SSRF access, approve an action, export audit and erase its actor; inspect durable outcomes with no secrets. Apply retention/hold settings and verify protected records and report denominators survive restart and cleanup.
-
PORTABILITY-001 — Complete customer-owned portable support data. Export versioned machine-readable conversations, attachments, contacts/companies, knowledge/versions, settings, rules/procedures/evaluations, outcomes and audit with a schema, integrity digest and explicit exclusions. Validate a bounded archive before atomic inactive restore to a clean installation; do not transfer sessions, provider secrets or connector authority and do not replay imported actions. Include D1, R2 and Durable Object business state or a lossless reconstruction; retain erasure fences and receiving-owner identity. This target replaces the current documented incomplete-storage boundary without pretending the held Base-data equivalence is done.
Acceptance evidence: Through rer export/import and owner data controls, populate each business store, export, destroy the disposable source and restore to a clean installation. Compare every portable record and attachment byte, preserve erasure fences, refuse corrupt/oversized/nonempty targets and verify all restored work is inert until separately authorized. Include Durable Object history and interrupted actions.
-
ASSURANCE-001 — Qualified regulated support deployments. US-first support uses USD, US provider contracts, IANA calendars and channel/recording consent controls. A regulated buyer can qualify an isolated deployment with required DPA/BAA, approved subprocessors/model data handling, access controls, audit, retention, incident response and validated deletion/export; health-data support is gated on those agreements and technical acceptance. The work remains a product obligation, with a named partner/provider path, rather than a claim that self-hosting alone supplies compliance.
Acceptance evidence: Before enabling a regulated workspace, an authorized administrator records required executed agreements/provider settings and runs tenant isolation, permission, audit, retention, recovery and erasure journeys with representative sensitive data. Missing agreements/controls block that configuration visibly; verify access only after qualification and withdrawal upon expiry/revocation.
Push further: accountable agents
-
PUSH-001 — Reproduce, repair and prove customer recovery. Given the conversation, authorized live product state and an explicitly paired repair workspace, the agent reproduces the customer's failure, records its observation, prepares or performs only the permitted fix, and verifies with a distinct post-change read or user journey. Environment, operations, data, spending and time limits are granted by a named person; production changes and reply publication have separate authority. Reconcile started/uncertain work, gather customer-scoped recovery evidence, report in the original thread and reopen/escalate if recovery fails or the customer reports recurrence. A successful command or closed engineering issue never proves recovery.
Acceptance evidence: Start with a real support request and reproducible product failure; pair the connector, run read-only reproduction, approve a bounded fix, independently observe the affected customer path and approve/send the original-thread report. Inject stale authority, uncertain change, failed verification, restart and later recurrence; verify no unapproved production effect/reply, truthful evidence and reopened ownership.
-
PUSH-002 — Promises survive every handoff. The agent extracts explicit commitments, quoted evidence and dependencies from messages and linked issues into durable obligations with a responsible person, due time, current evidence and stop condition. Chase missing evidence internally, detect stale dependencies and draft an honest customer update before a promise expires. Humans accept material due-date or promise changes; no fabricated progress, invented commitment or unapproved customer message is allowed.
Acceptance evidence: In a conversation promise a follow-up, link an engineering dependency, hand off twice and restart. Verify the same cited obligation, accepted owner/due-time changes, reminders and a timely draft; mark an evidence-free dependency stale and block any claim of completed progress until readback exists.
-
PUSH-003 — Learn from reopenings under human control. The agent joins reopened requests, complaints, CSAT, procedure/tool versions and connected business outcomes to identify failed resolution paths. Propose a concrete procedure/policy change with cited cases, replay evaluation and expected effect; a human approves changed permissions/tools, spending limits and bounded rollout. Track actual post-release recovery and regression, stop/rollback on deterioration and preserve original procedure versions and dissenting evidence.
Acceptance evidence: Create matched resolved/reopened cases under two procedure versions, inspect a proposed change and its replay set, reject then approve a limited rollout and inject regression. Verify only approved versions/actions run, before/after outcomes are attributable and rollback preserves all failure evidence.
-
PUSH-004 — Turn verified edge cases into reviewed knowledge. The agent identifies unanswered or repeatedly reopened topics from permitted conversations, support searches and procedure failures, clusters the gap and drafts a sourced article/update from verified resolutions. Strip personal data, obey private/brand/locale boundaries and include the evidence and proposed scope. A named editor reviews publication/translation and the agent measures whether later customers recover, proposing corrections when they do not.
Acceptance evidence: Resolve a previously undocumented case, trigger gap analysis, inspect a cited redacted draft, reject and then publish an edited version and ask the next customer's question. Verify permission-aware retrieval, no automatic publication, attribution and a corrective proposal when the case reopens.
Honest boundaries and connected products
HappyToHelp owns customer support, its operational queue, service follow-up and support CSAT. It consumes sales/customer context from Orbit, HubSpot and Salesforce; Buoy owns post-sale customer-success programs. Penny owns feedback aggregation, prioritization, roadmap/changelog and requester closure; Vector owns engineering issues and delivery. HappyToHelp links their records and follows the support request through verified recovery. General marketing campaigns go to Mango, incident subscriber communication to Lamp, general survey research to Pencil and employee IT service management to Linen. No neighboring product or unowned LIST gap is absorbed.
Aircall/Twilio and Meta operate the telephone/messaging networks and provider registration; HappyToHelp supplies the connected support experience, routing, consent and failure controls in VOICE-001 and CHANNELS-001. It does not become a carrier or emergency dispatch service: emergency callers are directed to 911 through the provider's supported routing and disclosed number/location limitations, while US emergency-calling obligations for supplied numbers must be qualified before voice launch. Stripe/Shopify execute authorized financial actions; HappyToHelp neither holds funds nor stores raw payment credentials. Commerce, CRM and subscription ledgers remain in their respective systems; complete support actions remain required here.
Arbitrary repair execution runs only in an explicitly paired external workspace, with per-operation authority, never as an implicit Worker capability. Provider apps, native apps, production integration qualification, health-data agreements, consent rules and payments-related support actions are engineering obligations in the named clauses, not reasons to reduce the target. Regulated deployments require ASSURANCE-001 qualification; no current HIPAA, SOC 2 or FedRAMP assurance is claimed. Provider acceptance is not customer receipt, a passing fixture is not a live deployment and a completed tool call is not a verified customer outcome. Existing accessibility and complete-storage holds remain in ACCEPTANCE.md until separately proven.
The platform admission index's move_in_contact_keys.email_digest remains lazy derived memoization. Exact business equality preserves its project/contact links and validates each populated digest against the native email; NULL-to-correct-digest does not alter business state. Contacts, native email, identity and all source/business links remain in the equality comparison.
Status
Judged from the code and tests at commit 82de9ed83c8d4f0b75c378fdd3e234015dc5fd5b (22 October 2026). R5 additionally updates SLA-001, AUTOMATION-001/002, QUEUE-001/004 and STATUS-001 from the workflow, inbox and packaged recovery journeys on 17 October 2026. WIDGET-001 and AUTOMATION-002 are re-judged at 473a30dab0c6458e5250a55cbebeef999e1e3063 (22 October 2026), with workspace presence and the away-reply correction (migrations 240 and 241). AUTOMATION-001 is re-judged DONE at c36c8cf01a3b8770427e78bed07d71159a0fb872 (23 October 2026).
WIDGET-001 remains PARTIAL pending its exact-head push Verify and post-Verify metadata re-claim. Public-door assertions now cover the during-hours response estimate and SLA-001 holidays/closures; the evidence row names the gate for each point. The retained live-model and hosted independent-domain qualification limits remain verbatim with AGENT-001 and NATIVE-001 respectively.
The 23 October 2026 contract-text clarification separates local implementation/fixture evidence from unobserved live qualification and records the interim knowledge permission default. It changes no clause status; all existing build and qualification obligations remain.
| Clauses | Done | Partial | Missing | Total |
|---|---|---|---|---|
| Published | 19 | 3 | 0 | 22 |
| Target and push further | 18 | 24 | 11 | 53 |
| All | 37 | 27 | 11 | 75 |
| Clause | Title | Kind | Status | Evidence | Gap |
|---|---|---|---|---|---|
NATIVE-001 | Native owner installation | published | partial | scripts/installer/local.mjs; scripts/installer/durable-objects.mjs; tests/helpers/installer/fresh-install.mjs, freshInstallJourney; tests/helpers/installer/readme-restore.mjs, readmeRestoreJourney: local commands, native owner/data and zero-outbound dry-run. | BLOCKED on Base: clean dependency-free rer describe installs dependencies before describing (including published rer 0.2.79). The separately started owner-consented read-only preflight remains unimplemented; real remote provisioning is separately unqualified. The inherited candidate dry-run builds locally without provider requests or credentials; the two acceptance steps remain distinct. P1/P2 real-mailbox delivery is qualified only from the local emitted application with the HH-owned sender and held fleet mailbox, not a hosted independently installed domain. |
IDENTITY-002 | Retained native password identity (owner decision 2026-10-08) | published | done | src/modules/identity/routes.ts; tests/journeys/identity.mjs (native passwords and membership: scoped sessions, owner resets and invitations retire with current authority; first-owner claim journey: validate and claim once under local, deployed and Managed installation authority; sign-in link journey: install-aware pages, neutral receipts and one explicit current-authority redemption) | |
IDENTITY-001 | Scoped authority | published | done | src/modules/management/policy.ts; tests/journeys/identity.mjs; tests/journeys/runtime.mjs | |
FIRST-RUN-001 | A useful first workspace | published | done | src/modules/management/provisioning/index.ts; tests/journeys/first-run.mjs | |
LOCAL-MAIL-001 | Rer dev mail | published | done | src/modules/integrations/email.ts; tests/journeys/first-run.mjs | |
CONVERSATION-001 | Durable transcript | published | done | src/modules/conversations/admission.ts; tests/journeys/runtime.mjs; tests/journeys/erasure.mjs | |
DELIVERY-001 | Live delivery and recovery | published | done | src/modules/conversations/socket.ts; tests/journeys/widget.mjs; tests/journeys/first-run.mjs | |
UI-001 | Existing editable experience | published | done | src/ui/dashboard; src/modules/widget; tests/journeys/inbox-browser.mjs (appearance settings journey); tests/helpers/inbox/settings-targets-browser.mjs (settingsTargetsBrowser: Settings target rectangles, one focus ring per switch and weekday, Notifications checkbox alignment, saving and reload at desktop width, with separate phone proof) | |
MOVE-IN-001 | Reviewed history import | published | done | src/modules/move-in/plan.ts; tests/journeys/move-in-capacity.mjs; tests/journeys/move-in-browser.mjs; tests/journeys/move-in-admission.mjs — “an approved import lands each vendor's history, people, replies, notes, tags and knowledge exactly, keeps notes private, and repeats or repackages as a no-op”; tests/journeys/move-in-custody.mjs — “publication meets later native changes safely: conflicts stop it before any write, a stopped publication resumes or undoes exactly, and guards stay bounded”; tests/journeys/move-in-erasure.mjs — “erasing a contact removes every import custody that holds them and refuses any later upload carrying their aliases, while other people's data stays” (original named steps retained in tests/move-in/native-corrections.mjs) | |
OUTCOMES-001 | Resolution feedback and provenance | published | done | src/modules/outcomes/rating.ts; src/modules/outcomes/operator-feedback.ts; tests/reports/ratings.mjs (visitor rating lifecycle: current session and cycle, bounded changes, commit races and erasure); tests/reports/outcomes.mjs (answer provenance: native and local proposals retain their original attribution through send and replay; resolution lifecycle: send, close, reopen and reassign atomically under current authority) | |
REPORTS-001 | Workspace calendar reports | published | done | src/modules/reports/routes.ts; src/modules/reports/metrics.ts; tests/reports/figures.mjs (report export journey: independent calendar oracles, complete bounded CSV and transcript export; workspace deletion journey: retained links, invitations and commit races never restore report authority); tests/journeys/reports.mjs | |
CONNECTIONS-001 | Workspace integrations | published | done | src/modules/api-integrations; tests/connections/api.mjs (API credential lifecycle: issue, use scoped operations, paginate, refuse lost authority and erasure, then revoke); tests/connections/delivery.mjs (delivery lifecycle: prepare, sign, dispatch, recover bounded work and require fresh approval for uncertain resend); tests/connections/slack.mjs (Slack notification lifecycle: deliver once with safe rendering and current workspace recipients) | |
ACTIVATION-001 | Observed owner setup | published | done | src/modules/management/activation; tests/journeys/first-run.mjs | |
AI-001 | Configured model execution | published | done | src/modules/ai-support/service.ts; tests/journeys/first-run.mjs | |
KNOWLEDGE-001 | Published knowledge | published | done | src/modules/knowledge/authoring.ts; src/modules/public-site/help-center.tsx; tests/journeys/knowledge.mjs; tests/journeys/public.mjs | |
CONTEXT-001 | Attributed customer context | published | done | src/modules/customer-context; tests/journeys/context.mjs | |
DELEGATION-001 | Explicit local authority | published | done | src/modules/local-computer/results.ts; src/edition/delegation/routes.ts; tests/journeys/delegation.mjs | |
TRAINING-001 | Durable evaluation | published | done | src/modules/training-runs/runner.ts; src/edition/ai/training.ts; tests/journeys/ai.mjs | |
INTEGRATION-001 | Honest external effects | published | partial | Local implementation/fixture evidence: src/modules/integrations/inbound.ts; src/modules/integrations/github.ts; tests/journeys/email.mjs (customer mail admission and suspended-message recovery preserve identity, authenticate gateways and admit each message once; automatic mail classification journey: original admission and recovery stay quiet while human mail notifies); tests/journeys/knowledge.mjs. Existing mail, inbound, GitHub and knowledge-import adapters exercise idempotency, suppression and outcome handling at local test/network boundaries. | Implementation/acceptance gaps: The required business connectors remain missing under COMMERCE-001, BILLING-001 and CRM-001. Live qualification gap: Real mail receipt, GitHub account authorization/events and provider-backed knowledge import are unobserved; adapter fixtures do not establish live delivery or account qualification. |
PUBLIC-001 | Public product source | published | done | src/ui/homepage; tests/homepage-browser.mjs; tests/journeys/public.mjs | |
MIGRATION-001 | Prior-data custody | published | done | src/modules/legacy-import; tests/journeys/erasure.mjs; tests/journeys/move-in-admission.mjs | |
SOURCE-001 | Author-owned capability graph | published | partial | scripts/edition-authoring/cli.mjs: authoring CLI, maintained capability graph and source-integrity checks. | tests/helpers/installer/edition-authoring.mjs, editionAuthoringJourney, runs inside the existing release-artifact test in tests/journeys/installer.mjs (Verify runtime-and-identity shard). It exercises CLI origin, local drift and executable-mode refusals, selected licensed release, excluded local credentials/private fixtures, clean-source refusal and receipt verification. Source integrity does not assert a product build or deployment; exact-SHA Verify remains required. |
DESK-001 | The shared support desk | target | done | src/modules/management/dashboard.ts; src/modules/management/inbox-search.ts; src/modules/tickets; tests/journeys/first-run.mjs; tests/journeys/inbox.mjs; tests/journeys/reports.mjs; tests/journeys/delegation-browser.mjs | |
WIDGET-001 | Availability-aware messenger and proactive messages | target | partial | R1 (SLA-001 calendars): tests/helpers/widget/presence.mjs — presenceJourney asserts public widget availability and the conversation's away reply for a US federal holiday and an explicit closure despite open widget hours, calendar edits and nonmatching-policy fallback; tests/helpers/widget/away.mjs — awayWidget asserts the installed closure notice, header and reply at 1440/390. P1 (outside hours): tests/helpers/widget/away.mjs — awayWidget asserts the notice and next opening in the visitor's timezone, captured email, native ticket and one away reply at 1440/390, then checks status sent and the mail-provider fake's recipient and exact answer text. P2 (during hours): tests/helpers/widget/presence.mjs — presenceJourney asserts default/configured Human response time in the away reply, including Accept new conversations off; tests/helpers/widget/presence-browser.mjs — presenceBrowserJourney asserts the configured estimate in notice, header and reply for nobody online and acceptance switched off at 1440/390, captures the email/ticket and checks status sent plus the mail-provider fake's recipient and exact answer text. P1/P2 prove local mail-boundary submission, not real mailbox receipt; mailboxLiveJourney is outside Verify and is not their cited gate. P3 (AI answer/disclosure): tests/helpers/widget/assistant-browser.mjs — assistantBrowser asserts an admitted provider-edge AI reply and persistent disclosure after edited copy and reload at 1440/390. P4 (configuration): tests/helpers/widget/campaigns.mjs — campaignsJourney asserts all seven triggers, audiences, sender/brand, permissions and stale-edit refusal; tests/helpers/widget/campaigns-browser.mjs — campaignsBrowser configures campaigns through Settings and exercises installed native/custom launchers at 1440/390. P5 (delay/cap): tests/helpers/widget/campaigns.mjs — campaignsJourney asserts the delay boundary, atomic daily cap, restart/day rollover and quiet hours; tests/helpers/widget/campaigns-browser.mjs — campaignsBrowser asserts the actual 20-second delay, dismissal and reload cap. P6 (sender/dismiss/consent): tests/helpers/widget/campaigns.mjs — campaignsJourney and tests/helpers/widget/campaigns-browser.mjs — campaignsBrowser assert sender/dismiss, consent/collector refusal, revocation and empty-composer opening without an automatic visitor message. campaignsJourney also asserts the ct-approved HH-RETENTION-001 30-day window through the 90-day report door while expired identifiers remain in a backlog, bounded scheduled/read cleanup and immediate revocation/native-erasure cleanup. P7 (reports): tests/helpers/widget/campaigns.mjs — campaignsJourney asserts deduplicated impressions/opens/dismissals and native conversation/resolution attribution including Closed-ticket follow-ups; tests/helpers/widget/campaigns-browser.mjs — campaignsBrowser asserts Reports rows and keyboard access at 1440/390. Verify registration map: presenceJourney is the workspace presence test and campaignsJourney is in the widget commands test in tests/journeys/widget.mjs; awayWidget is in installedJourney (the installed widget test), presenceBrowserJourney is the two teammates test, and campaignsBrowser/assistantBrowser are in settingsJourney (the widget settings editor test), all in tests/journeys/widget-browser.mjs. | DONE re-claim awaits successful push Verify on the exact handed-over head and the post-Verify metadata judgement. The required assertions are named in Evidence; no live-model or hosted-domain obligation is added to this clause. |
MAIL-001 | Complete support email | target | partial | Local implementation/fixture evidence: src/modules/integrations/mailboxes/; src/modules/integrations/email-threading.ts; tests/helpers/email/mailbox-provider.mjs; tests/helpers/email/complete-email.mjs; tests/helpers/email/transports.mjs; docs/email.md. Forwarding, Gmail and Microsoft 365 OAuth connections, aliases, branded sender, signatures, CC/BCC, header/token threading and cursor/reconnect/backfill/disconnect controls are asserted against network-edge fixtures in tests/journeys/email.mjs (customer mail admission and suspended-message recovery preserve identity, authenticate gateways and admit each message once; automatic mail classification journey: original admission and recovery stay quiet while human mail notifies). | Protocol evidence: tests/helpers/email/complete-email.mjs, imapSmtpJourney, independently registered in tests/journeys/email.mjs, drives src/modules/integrations/mailboxes/socket.ts through connection verification, fragmented IMAP greetings/commands/UTF-8 literals, UIDVALIDITY, cursor sync/backfill, reconnect and SMTP authentication/DATA. Only the TLS socket boundary is replaced; application admission, encrypted credentials and durable send stores assert redelivery without duplicate tickets/effects, cursor retention and inert automatic-mail redelivery. This is protocol fixture proof, not a real TLS server or live mailbox qualification. Live qualification gap: Real forwarding, IMAP/SMTP, Gmail and Microsoft 365 test accounts, domain/sender authorization, delivery, bounce/permission failures and production cutover are unqualified; simulated OAuth/provider responses do not qualify a real account. |
MAIL-002 | Reviewable suspended and spam mail | target | done | src/modules/integrations/suspended.ts; src/modules/integrations/suspended-store.ts; src/modules/integrations/suspended-recovery.ts; tests/helpers/email/complete-email.mjs; docs/email.md | R6 local scope complete: separate held-mail store, reasons/authentication/headers, safe text and attachment inspection, existing/new-ticket recovery, address/domain rules and audited 14-day expiry. Public-door journeys cover spoof isolation, permissions, recovery without retrospective effects and erasure. R6's browser check of recovery, allow/block/remove and deletion at 1440 and 390 has no repository journey and was not repeated for this review. |
OUTBOUND-001 | Agent-created and proactive tickets | target | partial | Local implementation/fixture evidence: src/modules/management/outbound-tickets.ts; src/modules/management/outbound-ticket-input.ts; src/modules/management/outbound-ticket-store.ts; tests/helpers/email/complete-email.mjs; tests/helpers/email/mailbox-provider.mjs; docs/email.md. Individual email and call creation implement requester/operator submitter attribution, mailbox and authorized sender, immutable CC/BCC, private call notes and durable send identity/outcomes. Network-edge fixture journeys inspect sent copies and threaded replies. tests/helpers/email/complete-email.mjs, in tests/journeys/email.mjs / “operators start email and call tickets, header and imported vendor replies preserve identity, suspicious mail stays in Suspended for safe audited recovery or expiry, and erasure removes its new stores”, proves new/existing requester creation and requester/submitter attribution, first-email header threading, immutable copies, call-note no-send, selected-mailbox authority, current-role races, a visible failed first-send outcome and exact retry without a second send or contact. tests/helpers/email/mailbox-provider.mjs proves provider-edge sent copies. | Browser evidence: tests/helpers/inbox/ui-browser.mjs, outboundTicketBrowser, independently registered as “New ticket creates email and call tickets with recoverable previewed service notices at 1440 and 390” in tests/journeys/inbox-browser.mjs, drives email/private-call creation, immutable replay, consent changes after preview and lost-response recovery. Definitive no-creation refusals retain the editable draft and usable Cancel, close and Escape; uncertain outcomes retain the same command. Service-notice evidence: tests/helpers/email/complete-email.mjs, outboundNoticesJourney, exercises preview confirmation, provider/refusal outcomes, consent refusal retained across later opt-in, and fifty requesters under enforced 1000-statement/call invocation meters. Remaining admissions resume under the immutable command after concurrent retries and native re-login. Durable notice commands live in outbound_notice_commands, independently of audit retention, for the lifetime of the workspace (no time-based command expiry). The workspace dialog intent is unique across operators and freezes its original actor, fingerprint and refusal or reservation before any admission. Ticket creation and first-message/outbox admission update the same command’s recovery IDs in their existing atomic batches; provider I/O remains outside transactions. Replays return already admitted tickets even after requester blocking, and reserved work keeps its original ticket identity. The existing email journey proves complete, reserved and partial replay after supported 90-day audit retention at day 91, native re-login and workspace isolation. No accepted or reserved command can become a notice_not_created certificate when its audit expires. The admission budget includes two additional statements per new notice recipient (ticket and outbox recovery receipts), each folded into an existing batch with no added D1 call. Scheduled abandoned-send reconciliation deliberately uses one additional statement/call compared with the previous main; the 1000-statement and 1000-call platform caps remain enforced. Each admitted message uses the durable outbox; lost dispatch, scheduled recovery and individual jobs finish without duplicate sends. Notification send execution is bounded to 60 seconds, including provider I/O; the scheduled pass reconciles sending claims older than 120 seconds without an open managed hold to uncertain with “the worker stopped during a send; check the provider before resending”. A send whose invocation died between claim and receipt is never retried automatically. The default remains 10 first-notice attempts per workspace per fixed UTC minute, with no batch CC/BCC. Capacity-deferred rows have no send claim; rate and consent refusals are terminal and visibly distinct from provider rejection. Implementation/acceptance gaps: Remaining form/field/brand/assignment configuration and consented SMS/WhatsApp template creation remain incomplete. Live qualification gap: Sending from an authorized real mailbox/domain and receiving the customer's real-mailbox reply are unobserved; inspected fixture copies do not prove delivery or live threading. Real-mailbox reply/cutover receipts are absent. WhatsApp sandbox credentials and an opted-in/out test number are not provisioned. |
CHANNELS-001 | Messaging and social support | target | missing | No implementation located. No SMS/Meta support channel implementation located. | |
CHANNELS-002 | B2B shared-channel support | target | missing | src/modules/api-integrations/dispatch.ts; tests/connections/slack.mjs; src/modules/escalations/actions.ts. Slack receives new-conversation notifications and outbound engineering handoff posts only, which this clause excludes; customer intake, bidirectional Slack Connect and Teams are absent. | |
VOICE-001 | Telephone service and unified voice agent | target | missing | No implementation located. No voice routing/agent or Aircall connector implementation located. | |
QUEUE-001 | Assignment rules and available teams | target | done | src/modules/workflows/routing.ts; src/modules/workflows/routing-candidates.ts; src/ui/native/pages/workflows/RoutingSettings.jsx; tests/helpers/workflows/routing.mjs | |
TRIAGE-001 | Intelligent triage | target | done | src/modules/triage/; src/modules/workflows/routing-triage.ts; tests/helpers/ai/triage.mjs; tests/helpers/ai/triage-browser.mjs; docs/triage.md | Configured-model classification runs after admission, with confidence, exact quoted evidence and native ticket fields. Operator labels measure accuracy before explicit intent-routing approval. Triage gates only rules with a triage condition; other routing rules act at admission whether the model is pending, down or unsure. An unsure or failed result places an unplaced ticket in the default queue once, never over a teammate's choice. Local API, dashboard, widget admission, erasure and rer archive journeys cover roles and custody. Live model quality is not claimed. |
QUEUE-002 | Structured and bulk queue work | target | done | src/modules/tickets; tests/journeys/inbox.mjs; tests/helpers/inbox/ticket-queue.mjs; tests/helpers/inbox/ticket-queue-capabilities.mjs; tests/helpers/inbox/tickets-browser.mjs | |
QUEUE-003 | Collaboration without conflicting replies | target | done | src/modules/collaboration; src/modules/conversations/socket.ts; src/modules/tickets; src/ui/dashboard/components/collaboration; tests/journeys/inbox.mjs; tests/journeys/first-run.mjs | |
MACRO-001 | Action macros with placeholders | target | done | src/modules/macros; src/ui/native/pages/macros; src/ui/dashboard/components/macros; tests/helpers/r4/macros.mjs; tests/journeys/inbox.mjs | |
QUEUE-004 | Snooze and scheduled follow-up | target | done | src/modules/workflows/schedules.ts; src/modules/workflows/routes-schedules.ts; src/ui/dashboard/components/workflows/WorkflowPanel.jsx; tests/helpers/workflows/schedules.mjs | |
STATUS-001 | Ticket status lifecycle | target | done | src/modules/tickets; src/modules/workflows/followups.ts; src/modules/workflows/rule-time.ts; tests/helpers/inbox/ticket-lifecycle.mjs; tests/helpers/inbox/ticket-api-privacy.mjs; tests/helpers/workflows/rules.mjs | |
SLA-001 | Business-hour service commitments | target | partial | Local implementation and fixture evidence: src/modules/workflows/calendars-time.ts; src/modules/workflows/sla.ts; src/modules/workflows/sla-alerts.ts; tests/helpers/workflows/sla.mjs. Local workflow journeys implement and assert calendars, first, next and resolution clocks, queue due times, pauses and durable acknowledged alerts using controlled clock and runtime edges. Rule and SLA notices use R4's proven-address delivery claims. tests/helpers/workflows/sla.mjs, in tests/journeys/inbox.mjs / “tickets carry typed fields, scoped teams and lifecycle history through customer replies, saved views, previewed bulk changes, the API and erasure”, proves two settings calendars and policies, holiday and repeated-DST-hour calculations, the exact due time and pause reason in the queue API, breach and workload report reconciliation, named breach and unattended backup alerts, the backup’s readable inbox with email unavailable, acknowledgment, deduplication and restart; both On-hold choices and Pending pausing; and the hand-calculated next-response due time after a solved ticket reopens. tests/helpers/request-forms-journey.mjs in tests/journeys/knowledge.mjs / “a translated request form enforces typed conditional required fields on the server, protects anonymous submissions, and admits one ticket after email verification” proves form and answer policy matching, exclusions and restart. tests/helpers/workflows/sla-slack.mjs — slaSlackFlow, within the existing tickets journey in tests/journeys/inbox.mjs, proves explicit same-workspace destination consent, approaching, breach and unattended delivery to named backups, metadata-only messages, provider refusal, bounded rate-limit retries, uncertain effects without replay across restart, acknowledgment, current backup removal, missing and revoked policy consent, revoked installing authority, wrong-workspace and wrong-role refusal, and explicit test-post consent. tests/helpers/workflows/sla-slack-browser.mjs — slaSlackBrowser, within ticketsBrowser in tests/journeys/inbox-browser.mjs, proves saving an SLA-only Slack connection, selecting its policy destination, and inspecting pending, failed, uncertain and acknowledged states; browser receipts show those screens at 1440 and 390. | Implementation gaps: Teams escalation delivery remains unimplemented. Ct ruling HH-SLA-SLACK-001: APPROVE WITH RIDERS (27 October): only an owner or admin may explicitly select an enabled workspace Slack destination; alerts freeze that destination and send fixed ticket and named-operator identifiers with metric and kind, excluding customer content, names, addresses and private notes. Acknowledgment stays in HappyToHelp and stops pending sends; it does not send a Slack callback or update. Removed backups, disabled destinations, policy opt-out and resolved tickets stop unsent alerts. Installation uses the same owner or admin authority as Teams ESCALATION-001; current installing authority is rechecked before sending. Saving a connection never sends a test: the separate Send test action is explicit test-post consent. Missing or revoked policy consent, wrong workspace and revoked installing authority refuse outbound delivery. Only explicit Slack rate-limit refusals retry, at most five total attempts; unknown effects and interrupted claims never replay. SLA-001 stays partial pending Teams parity, live Slack receipt and exact-SHA evidence. Live qualification gap: Real mailbox receipt and live Slack and Teams escalation delivery and acknowledgment receipt remain unobserved; local network-edge receipts are protocol evidence only. No Slack sandbox credential or Teams tenant is supplied. NOTIFY-001 and CHANNELS-002 inherit no personal Slack or bidirectional-channel delivery claim from this slice. |
AUTOMATION-001 | Explainable durable support workflows | target | done | Settings and sandbox: tests/helpers/inbox/tickets-browser.mjs, in tests/journeys/inbox-browser.mjs / “ticket settings and ticket fields save through the dashboard at desktop and phone widths”, configures route/tag/status/note/reminder/customer-update actions, previews with no effects, explicitly publishes an immutable version and pauses it at 1440 and 390. Execution: tests/helpers/workflows/rules.mjs, in tests/journeys/inbox.mjs / “tickets carry typed fields, scoped teams and lifecycle history through customer replies, saved views, previewed bulk changes, the API and erasure”, proves responsible lead, matching/nonmatching requests, ordered/versioned actions, historical sandbox suppression, signed-webhook success/refusal/uncertainty, interrupted claims, current receiver authority, restart and pause without replay. Permitted notifications and reconciliation: tests/helpers/r4/notifications.mjs, in tests/journeys/email.mjs / “editable requester triggers send received and solved once, suppress historical and machine mail, and teammate notices follow current authority and preferences”, proves one assignee and requester/proven-CC send, current named-group/follower audiences and preferences, explicit failures/unknown outcomes, stopping later actions, restart, pause and guarded manual review. Native runtime and network-edge assertions establish this clause; no live-provider delivery qualification is claimed. | ADOPTED policy: review cancels all remaining actions, preserves existing provider uncertainty and never resumes or replays work. Live qualification gap: Real notification-provider delivery and signed-webhook receiver acceptance are unobserved; local sandbox/outcome assertions do not qualify either. |
AUTOMATION-002 | Time-based automations | target | done | src/modules/workflows/rule-time.ts; src/modules/workflows/rule-engine.ts; src/jobs.ts; tests/journeys/inbox.mjs; tests/helpers/workflows/rules.mjs | Hourly durable time automations, the 48/96 business-hour templates, the seeded four-day close, restart-safe cursors, customer-reply reset, unsafe-repeat refusal and automation actors pass their journeys. The last-agent-update time (src/modules/workflows/time-rules.ts, src/modules/workflows/rule-model.ts) counts a teammate's reply and never the workspace's system away reply (migration 241), so an agent-update automation waits for the teammate's reply (tests/helpers/workflows/rules.mjs). |
NOTIFY-001 | Customer acknowledgments and teammate notifications | target | partial | Local implementation/fixture evidence: src/modules/integrations/triggers.ts; src/modules/integrations/triggers; src/modules/integrations/notification-teammates.ts; src/modules/integrations/operator-notifications.ts; tests/journeys/email.mjs; tests/journeys/inbox.mjs. Local network-edge journeys assert editable requester/proven-CC received and solved notices, teammate inbox/email preferences, frozen delivery claims, machine/import/merge suppression and uncertain-send fences. The workflow notification interface uses the same proven-address delivery claims (src/modules/workflows/notify.ts lines 3,36; src/modules/integrations/notification-actions.ts lines 17). tests/helpers/r4/notifications.mjs, in tests/journeys/email.mjs / “editable requester triggers send received and solved once, suppress historical and machine mail, and teammate notices follow current authority and preferences”, proves requester/proven-CC acknowledgment and redelivery suppression, widget admission, machine/import suppression, assignment/follower/mention/group audiences, current permissions/preferences, revoked recipients, template failures, loop headers and durable uncertain outcomes. Its workflow actions additionally prove assignee/customer, explicitly selected current-group and follower recipients, foreign-group refusal, preference-respecting email/inbox delivery and restart without replay. tests/helpers/request-forms-journey.mjs in tests/journeys/knowledge.mjs proves one verified requester acknowledgment and separately addressed proven-CC acknowledgments across replay/restart, with no recipient leakage. Valid unknown, ambiguous, unproven or other-workspace CC addresses are silently omitted with the same public success shape; malformed addresses still fail validation. Normalized requester self-duplicates add no participant or extra acknowledgment. Typed CCs create no identity; changing the CC command conflicts. | Implementation/acceptance gaps: Mobile push and personal Slack/Teams delivery are unimplemented; no Slack bot sandbox credential, push application or Teams test tenant is supplied. The clause stays partial. Live qualification gap: Real requester/CC/teammate mail receipt and live Slack/Teams or push-account delivery are unobserved; proven-address claims and fixture receipts are not live delivery evidence. |
CONVERSATION-002 | Merge and external forwarding | target | done | src/modules/conversation-actions; src/ui/dashboard/components/conversation-actions; tests/helpers/r4/conversation-actions.mjs; tests/journeys/inbox.mjs | |
CONVERSATION-003 | Problem and incident linking | target | partial | Local implementation and fixture evidence: src/modules/tickets/problem-routes.ts; src/modules/tickets/problem-execute.ts; tests/helpers/inbox/problems.mjs; docs/tickets.md. Local journeys assert manual and bulk Problem and incident linking, requester-specific placeholder previews, email and widget replies, independently confirmed solve and failed-send open states, per-ticket history and audit, erasure and safe restore. tests/helpers/inbox/problems.mjs, in tests/journeys/inbox.mjs / “tickets carry typed fields, scoped teams and lifecycle history through customer replies, saved views, previewed bulk changes, the API and erasure”, proves previewed 25-incident linking, requester-rendered replies, email and widget isolation, per-ticket failures and status, unlink-before-solve isolation, history and audit and erasure. It also proves an engineering issue on the Problem, signed closure and duplicate suppression, one unsent approval draft, unconfirmed recovery, explicit stale context after disconnect and restart. The same journey proves per-incident SLA and CSAT invitations: under one SLA policy each incident's resolution commitment starts from its own request, each solved incident completes its own running commitment at its own solve, and incidents left open by a failed or blocked reply or unlinked before the solve keep theirs running; a second Problem whose incidents arrived through the widget from signed mailboxes sends exactly one CSAT invitation per solved ticket, to its own requester, and none for the incident unlinked before the solve. The existing roles and security log journey in tests/journeys/identity.mjs (tests/helpers/identity/roles-audit.mjs) proves collaborator and reply-only custom-role refusal at all six suggestion mutation doors, and successful operator preview, rejection and confirmation at both mounts. Local deterministic triage suggestions are proved in the existing ticket lifecycle journey (tests/helpers/inbox/problems.mjs): same-workspace active Problems matched by shared subject terms, operator-owned preview and explicit single-use confirmation, rejection without mutation, expired and stale previews on either ticket, foreign-tenant and revoked-role denial, audited unlinking and zero automatic sends. The existing “ticket settings and ticket fields save through the dashboard at desktop and phone widths” journey in tests/journeys/inbox-browser.mjs (tests/helpers/inbox/tickets-browser.mjs, with tests/helpers/inbox/problem-suggestions-browser.mjs) proves discovery, inspection, rejection, stale-preview recovery and the resulting link; browser receipts show those screens at 1440 and 390. | Implementation and acceptance gaps: SMS consent and reply-window transport and its live Twilio receipt remain unavailable (TWILIO_AUTH_TOKEN is not provisioned). The clause stays partial for SMS and live delivery qualification. Live qualification gap: Real email receipt and SMS provider delivery and window enforcement for linked incidents are unobserved; email fixtures and local widget observations qualify only those local paths. |
CUSTOMER-001 | Customer and company support records | target | partial | Local implementation/fixture evidence: src/modules/customers; src/modules/import-kit/csv; src/ui/native/pages/Companies.jsx; tests/helpers/company-records.mjs; tests/helpers/customer-csv.mjs; tests/journeys/inbox.mjs. Local journeys assert companies, typed attributes, domains, membership, account ticket lists, inbox filtering, previewed reversible merge with provenance and mapped CSV preview/apply/undo. Imports send nothing; erasure, audit and portable stores are covered locally. tests/helpers/company-records.mjs, in tests/journeys/inbox.mjs / “workspace management keeps settings, resources, bootstrap, owners, notes, participants, transcript mail, widget origins, presence and mailbox ownership within each workspace's current authority”, proves typed account attributes, membership, account merge preview/undo and provenance, role/tenant fences, and independently verified identity association preview/apply/unlink. It also proves stale-preview refusal, live-session and proof-loss races at commit, symmetric provenance after restart, no send, erasure of either identity or provenance naming a third customer, refusal to replay a pre-erasure preview, and no shared customer history. tests/helpers/customer-csv.mjs, in the same journey, proves mapped contacts/company CSV preview, invalid/duplicate handling, apply/undo and no send. tests/helpers/context/identity-links-browser.mjs, in tests/journeys/inbox-browser.mjs / “the management libraries: contacts, saved replies, assistants, plugins and members are listed, edited, validated and removed, …”, proves the operator screen at 1440 and 390: an owner opens a customer from their company, sees the labelled “Possibly the same customer” context view, is refused linking a typed email, previews and confirms a link to a verified identity, shown in the requester's ticket with its reviewer and date under Ticket › Customer, with the full evidence on the customer page, unlinks it with a reason, and reads both decisions in the link history and the Security log, while message counts, both customer records and each customer's own widget session are unchanged. tests/helpers/company-records.mjs also proves that the link history keeps reviewer, time and evidence after unlinking and that erasure removes it. | Implementation/acceptance gaps: Full cross-channel identity governance and live connector context remain incomplete. Stored company/domain membership is not proof of external account entitlement. Identity association has an operator screen on the customer page (src/ui/native/pages/companies/CustomerIdentityLinks.jsx, docs/WORKSPACE-WORKFLOWS.md) that implements the ct ruling below as staff context only, with link history in migrations/252_customer_identity_link_history.sql. Named Gap — ct ruling, 23 October 2026 12:11Z: interim default = a reviewed identity link gives the operator context only (a labelled “possibly the same customer” view inside the workspace, audited), never customer-side access, merge or send authority. Target (named Gap) = an operator-confirmed link may show the linked history to staff in the same workspace under ROLE scope, with reviewer, time and evidence kept and the link reversible; nothing is merged, no message is sent because of a link, and customers see only what their own verified session allows. Live qualification gap: Verified chat/email/social identity linkage and fresh/stale business-system context against real accounts are unobserved; synthetic contacts, domains and CSVs do not qualify them. Provider-backed chat/email/social linking and business-system context with live sync/disconnect receipts remain unqualified; no social-provider sandbox is held. |
COMMERCE-001 | Shopify order actions | target | missing | No implementation located. No Shopify order/refund connector implementation located. | |
BILLING-001 | Stripe billing and subscription resolution | target | missing | No implementation located. No active Stripe billing/subscription action connector located; legacy financial imports confer no action authority. | |
CRM-001 | Live CRM and account context | target | partial | tests/journeys/connections.mjs — “read-only HubSpot context uses explicit customer mappings, refreshes changed source fields and refuses stale authority, identity conflicts and unavailable grants without customer access” (tests/helpers/hubspot-context.mjs): exact read-only scopes and account check; explicit contact and company source IDs; changed plan and entitlement context through ticket refresh; timestamps and stale state; conflicting mapping, identity mismatch, permission loss, disconnect, cross-workspace and customer denial, session and disconnect races, erasure, redirect and response bounds. | HubSpot native API foundation only. Settings connection and mapping screens, ticket and customer panels, 1440 and 390 browser proof, live HubSpot qualification, Orbit, Salesforce and approved CRM writes remain unproved. Conservative default ADOPTED pending ct approval: owner or admin only with native permissions, exact contact and company read scopes, explicit source mapping with email and company-domain plus association checks, no automatic matching or CRM-derived customer access; failed refreshes clear cached context and reconnect clears mappings. Imported and restored archives clear CRM credentials and cached personal context, mark mappings stale and require explicit reauthorization, including older archives. Authorized support operators still need relevant CRM context on their own work: it is not yet shown to them in their ticket and customer panels. Approved CRM writes remain contracted and unproved. CRM-001 remains partial. |
ESCALATION-001 | Engineering and team escalations that return | target | partial | Local implementation and fixture evidence: ./src/modules/escalations; tests/journeys/connections.mjs; tests/journeys/connections-browser.mjs; tests/helpers/escalations/dev-proof.mjs. tests/journeys/connections.mjs and tests/journeys/connections-browser.mjs use local HTTP GitHub, Linear, Jira and Slack fixtures: 40 tickets, 12 issues, 3 handoffs, one issue linked from 5 tickets, private and unchosen exclusion, forged, duplicate and older webhooks, assignee and status, owner inbox, edited approved drafts, recovery observation, collaborator refusal and erasure. tests/helpers/escalations/dev-proof.mjs lines 11-17 starts rer dev --foreground, opens its RER_OPEN entry and repeats the UI at 1440 and 390. Export strips credentials and restore retains disconnected links. | Teams deterministic evidence: tests/helpers/escalations/journeys.mjs, sharingJourney and teamsSharing, through tests/journeys/connections.mjs — selected messages and attachments, private and unchosen exclusion, reciprocal ticket and Teams message links, concurrent and duplicate requests, revoked installing authority, explicit provider refusal, unknown delivery without replay, and a customer-visible update only after operator Send. teamsUpgrade proves existing provider references survive migration. tests/helpers/escalations/browser.mjs, exerciseEscalations, through tests/journeys/connections-browser.mjs proves channel selection, preview, confirmation, linked result, refusal and uncertainty at 1440 and 390. Its existing phone journey measures every visible Teams connection control, tracker anchor and handoff control, including Save Teams connection and Refresh status, and requires targets of at least 44 by 44 pixels. It also checks that refused, uncertain and revoked-provider outcomes are fully visible immediately after Share; the landing proof captures the same screens at 1440 and 390. Implementation gaps: A Teams escalation must also return authenticated status, owner notification, a reviewable customer update, and separately observed recovery; these return-path obligations remain unproved for Teams. Teams signed inbound status and fix-shipped draft automation remain absent; ordinary operator Send is required for Teams customer updates. ct batch 14 approved this outbound slice with riders; ESCALATION-001 stays partial. The built slice uses owner or admin installation of one fixed Teams channel, current installing authority rechecked before sending, selected public context only, plain text without mentions, and no automatic replay or customer publication. Remaining Slack SLA riders also apply: consent authority must align, five total attempts permit retries only after an explicit rate-limit refusal, and missing refusal cases still need proof. CHANNELS-002 and NOTIFY-001 inherit their own installed-channel and consent obligations; this outbound slice grants no inbound authority. Live qualification gap: Real GitHub, Linear, Jira, Slack and Teams account scopes, status callbacks and delivery remain unqualified; loopback protocol evidence does not qualify live accounts. |
API-001 | Owned API and managed connectors | target | partial | Local implementation/fixture evidence: src/modules/api-integrations; local-agent/lib/mcp.mjs; src/modules/move-in/plan.ts; tests/connections/api.mjs (API credential lifecycle: issue, use scoped operations, paginate, refuse lost authority and erasure, then revoke); tests/connections/delivery.mjs (delivery lifecycle: prepare, sign, dispatch, recover bounded work and require fresh approval for uncertain resend). Native scoped API/webhooks, Help Scout export import and connector MCP transport exist. Local public-door and network-edge journeys assert guarded API operations and webhook protocol behavior; synthetic export import is distinct from continuous synchronization. | Implementation/acceptance gaps: Managed connector catalog, Zapier actions/triggers and continuous Help Scout API/webhook synchronization are absent. Live qualification gap: Real webhook receiver acceptance, Zapier account execution and Help Scout account scopes/cursors/reconnect are unobserved; native API and export fixtures do not qualify managed provider connectors. |
API-002 | Create and append support requests from another product or agent | target | missing | Native public-route evidence: tests/connections/api-create.mjs / “machine create credentials admit one atomic ticket and replay across rotation without granting other scopes” covers create/replay and identity fencing; customer/note attachment and status matrices; configurable requester holds and 429 headers; signed ordered events, retries and credential filtering; overlap, expiry, revocation, binding-change and deleted-workspace admission races; and owner-readable API erasure counts with pending-payload removal. tests/journeys/connections-browser.mjs / “at 1440px…” and “at 390px an owner creates and revokes a token…” exercise create-only, append-only, read-only and full machine credentials, one-time secrets, Settings metadata and a working operator source back-link. tests/helpers/recovery/journey.mjs / verifyRestoredApi, through tests/journeys/restore.mjs / “a populated packaged install restores…”, adds API metadata, revoked-token, digest and erasure-fence restore assertions; exact-candidate CI qualification is required. Additional deterministic evidence in the same API phase covers literal content-abuse holds across subject, body and source reference, no ticket/event/AI/outbox effect while held, reviewed release and native triage input; installation-admin workspace suspension with next-request 401 and atomic admission; and issuer erasure with retained machine history, redacted audit/export identity and revoked credentials without hashes. tests/helpers/identity/roles-audit.mjs / rolesAuditJourney qualifies both member-erasure route permissions. tests/helpers/recovery/journey.mjs / eraseRecoveryIssuer and verifyRestoredApi, through the populated restore journey, qualify issuer redaction and machine-event retention across export/restore. Owner transfer and installation review are required for owners and shared accounts respectively. Authority-model evidence: tests/connections/api-create.mjs / apiInvariantSweeps derives conversation-door coverage from the mounted router, crosses requester admission with every key spelling, checks one credential across rotation and policy changes, snapshots all foreign-workspace rows during erasure, and compares released tickets with direct creates. tests/connections/migration.mjs retains a populated legacy bearer grant across the credential backfill. The existing Settings browser journeys verify one credential card containing its rotated secrets at 1440 and 390. Repair scope: shared credential scope eligibility, isolate-cached schema-derived member-erasure scope with generated workspace deletes and reset/invite row separation; key-driven contact, sender-rule and digest-fence admission; indexed verified email/external/phone identity matching in create and release; reach-filtered credential replay/conflict references; operator-visible release collision IDs; and shared requester insertion. The existing scale sweep meters append, create and release doors with contacts, sender rules and both fence tables populated. API-002 remains missing pending exact-candidate verification and the independent gate. Remaining gaps: live AI content-abuse and complete triage/AI qualification, including “body text, subject and source fields can never instruct the agent or open an external effect.” Point 9 (consent-gated SMS/WhatsApp acknowledgment) is out of scope pending CHANNELS. No Handset or live delivery qualification. | |
MOVE-IN-002 | Switch from every named incumbent | target | partial | tests/journeys/upgrade.mjs, priorSchemaUpgrade with attachmentSchemaUpgrade in tests/reports/upgrade-attachments.mjs: native public and private media and transcripts remain readable before the attachment table or its required columns exist, retain exact native bytes after migration and deny visitor access to private files. tests/move-in/supplied-attachments.mjs, attachmentJourney folded into the existing Freshdesk scenario in tests/move-in/door-mapping.mjs: explicit Freshdesk NDJSON bytes, digest and size rejection, native message and private-note ownership, current-role denial, bounded apply, resume and repeat, exact unchanged undo, native-edit conflict preservation and erasure with replay denial and unrelated payload retention; imports make no outbound request. tests/move-in/attachment-browser-flow.mjs, attachmentBrowserFlow folded into the existing Move in browser journey: supplied mappings and omissions, apply and native public and private attachment downloads at 1440 and 390. Local implementation and fixture evidence: tests/journeys/move-in-admission.mjs; tests/move-in/door-readers.mjs — “refusals: refused uploads are located at their exact source place before any custody, queue, native write or outbound call” and “review: an accepted export is reviewed with each record's kind, ID, payload, exact location, duplicates, conflicts and reasons before anything is approved”; tests/move-in/helpscout-security.mjs — “helpscout: Help Scout conversations and Docs publish only complete public content, recheck category privacy, and keep undo and erasure safe”: documented four-vendor upload, review and apply, roles, omissions and history. tests/journeys/move-in-capacity.mjs: bounded resume, repeat and undo and custody. tests/move-in/door-mapping.mjs, lifecycleJourney and configurationJourney (steps in “landing: an approved import lands each vendor's history, people, replies, notes, tags and knowledge exactly, keeps notes private, and repeats or repackages as a no-op”); tests/move-in/configuration-fields.mjs, configurationFieldsJourney: source timestamps, lifecycle, private notes, typed Zendesk fields and inert configuration. tests/helpers/email/vendor-replies.mjs, vendorReplies: threading and reviewed ownership. tests/move-in/companies.mjs, companyJourney: documented company and default-membership mappings for all four vendors, portal access off, domain conflicts and exact repeat and undo; configurationBrowser in tests/journeys/move-in-browser.mjs opens the imported company and member at 1440/390. | Implementation and acceptance and live qualification gaps: Attachment bytes for Zendesk, Intercom and Help Scout, metadata-only Freshdesk exports, larger or unsupported Freshdesk payloads, final delta and explicit channel repoint remain incomplete. Freshdesk byte admission requires explicit canonical base64 and digest, at most 48 KiB each and 20 per ticket, within existing record and upload bounds; private notes retain teammate-only access. No automatic URL retrieval or sends are introduced. Full custom fields and configuration and multiple-company fidelity remain incomplete: Zendesk maps the explicit default, Freshdesk the primary, Help Scout organizationId, and Intercom only a complete single-company relationship; omissions are explicit. Real vendor API and account ingestion and a new live message after cutover remain unobserved. Company and configuration browser qualification passed at 1440/390; export upload is already a supported alternative to API connection. |
MOVE-IN-003 | Replies to pre-migration mail land in the imported ticket | target | partial | Local implementation/fixture evidence: tests/helpers/email/vendor-replies.mjs, vendorReplies, through tests/journeys/email.mjs, completeEmailJourney: all four vendors’ old Message-ID chains and reply addresses; documented Zendesk/Freshdesk/Help Scout subject schemes; explicit current-member/group activation; owner/group/requester preservation on Solved reopening; each supported matching method reopens Solved history and links a follow-up to final Closed history; wrong-customer review and unmatched hints. Exact-repeat, whole-undo, reimport and contact-erasure assertions cover the four vendors’ keys. Role/membership changes refuse stale activation and activation sends nothing. tests/move-in/door-mapping.mjs, lifecycleJourney (steps in “landing: an approved import lands each vendor's history, people, replies, notes, tags and knowledge exactly, keeps notes private, and repeats or repackages as a no-op”): source lifecycle/channel and exact undo of inert keys. | Implementation/acceptance and live qualification gaps: Intercom has no invented subject-token scheme. Existing older imports without assignment snapshots remain unactivated. Live incumbent notification/export accounts and actual support-channel cutover are required for the outstanding real-mail qualification. |
MOVE-IN-004 | Bring configuration, not only history | target | partial | Local implementation/fixture evidence: tests/move-in/door-mapping.mjs, configurationJourney (steps in “landing: an approved import lands each vendor's history, people, replies, notes, tags and knowledge exactly, keeps notes private, and repeats or repackages as a no-op”): Zendesk macro placeholders/four actions, two groups, views, inactive schedules/holidays and draft event/hourly rules; native preview/publication, exact repeat/undo and later native-edit protection. tests/move-in/configuration-fields.mjs, configurationFieldsJourney: typed ticket values, two disabled forms, option labels/values, explicit publication and refusal of restricted/conditional forms. tests/journeys/move-in-browser.mjs, configurationBrowser: per-item omissions, native settings links and previews at 1440/390. | Implementation/acceptance and live qualification gaps: The bounded Zendesk mapping does not establish full source equivalence: memberships/defaults, SLA policies, brands and full help-center structure remain incomplete, as do the other vendors’ configuration equivalents. Native automation journal/hour-boundary semantics are disclosed. Real vendor configuration/API sandbox equivalence remains unobserved. |
PORTAL-001 | Authenticated customer self-service | target | done | src/modules/portal; src/modules/public-site/portal-pages.ts; src/modules/customers; tests/helpers/customer-portal-journey.mjs; tests/helpers/company-portal.mjs; tests/journeys/knowledge.mjs | Email-link sign-in, request flows, attachments and preferences include explicit per-company ticket visibility, off by default. Current membership and entitlement fence list, detail, reply, reopen and attachment access; removals take effect on the next request. Local runtime journeys establish these paths; no live email-provider qualification is claimed. |
FORMS-001 | Customer request forms with custom fields | target | partial | Local implementation and fixture evidence: src/modules/forms/settings.ts; src/modules/forms/definition.ts; src/modules/forms/validation.ts; src/modules/forms/challenge.ts; src/modules/forms/submit.ts; src/ui/native/pages/request-forms/RequestFormsSettings.jsx; tests/helpers/request-forms-journey.mjs; tests/helpers/self-service-fixture.mjs; tests/journeys/knowledge.mjs. Local journeys assert typed ticket fields, required and conditional questions, locale labels, server refusal of invalid and hidden values, verified email identity and fail-closed Turnstile boundary responses for anonymous submissions. Verified customer sessions submit without Turnstile. tests/helpers/request-forms-journey.mjs, in tests/journeys/knowledge.mjs / “a translated request form enforces typed conditional required fields on the server, protects anonymous submissions, and admits one ticket after email verification”, proves conditional required, regex and hidden-field validation, Spanish labels, verified customer admission and replay, once-only acknowledgment, challenge denial, typed values selecting routing and SLA, nonmatching exclusions, field and form version history, old values, restart, stale-save and field-read restrictions. tests/helpers/inbox/tickets-browser.mjs, in tests/journeys/inbox-browser.mjs / “ticket settings and ticket fields save through the dashboard at desktop and phone widths”, proves policy display and editing preserving form and typed conditions at 1440 and 390. tests/helpers/account-lookup-journey.mjs, extending the existing translated request-form journey in tests/journeys/knowledge.mjs, proves native account configuration, authenticated choice scoping, forged and foreign IDs, hidden, merged and revoked choices, portal visibility off with a published field, portal visibility on with an unpublished field, membership and publication and field-permission revocation at commit, historical values through upgrade and restart, operator edits and field permissions. tests/helpers/account-lookup-browser.mjs, extending the existing ticket-settings journey in tests/journeys/inbox-browser.mjs, proves account field configuration, aligned phone switches with 44 px targets, workspace account choices for form conditions, email verification in another tab refreshing the open form without losing the draft, a clear no-account contact path, revoked selections cleared synchronously with field-specific refusal while keyboard focus stays on the account field after empty choices refresh, removed questions transfer refusal focus to the result message, empty account conditions retained across save and reload without choosing an account, submission retaining ordinary typed answers, named ticket values and history, and a saved-view account filter. The same existing journeys assert field-specific revoked-account refusal with the dependent answer both empty and filled, reject saved-reply account names and foreign or merged identifiers, and preview canonical account changes with company names. The browser journey configures saved-reply account choices without free text and inspects named account changes on the ticket. Browser captures and control measurements cover 1440 and 390. The existing account journey also inspects raw public list, detail, rendered pages, refresh offers and admission refusals for anonymous visitors, eligible members, customers with no membership and revoked members. Account predicates are evaluated on the server against currently eligible selections; customer responses carry only visibility results, never account condition values. | Implementation and acceptance gaps: Order lookup remains incomplete. Native account lookup uses a verified current customer identity and current explicit membership in an unmerged account in the same workspace. An authorized owner or admin deliberately publishes the customer-facing account field by including it on a published form; only eligible account identifiers and labels are disclosed. Eligibility is independent of company-wide portal ticket visibility. Identity, membership, eligibility, publication and field permissions are checked at offer and admission, including guarded writes; forged, foreign, hidden, merged and revoked choices receive field-specific refusals. No membership is derived from domains. The quoted ct alternative is implemented; final ct approval remains pending. Future order lookup must inherit the same current-authority checks. Live qualification gap: Real Turnstile hostname and site-key verification and mail-provider delivery and verification links remain unobserved; simulated challenge and mail responses are fixture evidence only. Live Turnstile and mail delivery receipts are absent; FORMS_TURNSTILE_SECRET_KEY is not provisioned. Historical form and field versions and their values are retained, but do not qualify live providers. |
KNOWLEDGE-002 | Governed private and multilingual knowledge | target | partial | Local implementation/fixture evidence: src/modules/knowledge/access.ts; src/modules/knowledge/experience.ts; src/modules/knowledge/experience-routes.ts; src/modules/knowledge/help-auth.ts; src/modules/knowledge/public-sources.ts; src/modules/public-site/help-center.tsx; tests/journeys/knowledge.mjs. Local route journeys cover public and signed-in/email-domain collections, reviewed translations, article history/restore and slug redirects. The assistant uses public-audience articles only, so restricted knowledge is excluded from answers. Email-domain membership is an audience gate, not account/company entitlement. | Implementation/acceptance gaps: Explicit account/company-entitled collections and permission-aware restricted agent retrieval remain incomplete; per-brand domain publishing and agent-proposed cited changes are absent. Existing email-domain gates do not satisfy the account-only acceptance. Live qualification gap: Custom-domain/DNS publishing, real customer mail authentication and account/company entitlement from a real account system remain unobserved; local audience fixtures do not qualify them. |
KNOWLEDGE-003 | Branded help center, article feedback and knowledge in the ticket | target | partial | Local implementation/fixture evidence: src/modules/knowledge/feedback.ts; src/modules/knowledge/analytics-routes.ts; src/ui/native/pages/knowledge/KnowledgeExperience.jsx; src/ui/dashboard/components/ArticlePicker.jsx; src/modules/public-site/help-center.tsx; src/modules/public-site/request-pages.ts; tests/journeys/knowledge.mjs; tests/journeys/public.mjs. Plain-text templates (home, category, section, article, search and request form), votes/comments, locale/brand activity analytics and recipient-scoped article insertion are implemented. Local journeys cover templates, search/view/click activity, feedback and insertion; no journey exercises the request-form template. | Implementation/acceptance gaps: Per-brand custom domains and ticket-after-reading attribution remain incomplete; request-form template acceptance is unproved. Live qualification gap: Real brand-domain/DNS/TLS publishing and customer mail delivery of inserted links remain unobserved; local host/template fixtures do not qualify domains or receipt. |
BRANDS-001 | Multi-brand support operations | target | done | Configuration and shared team, reception/resolution in each brand, one-brand policy changes and denied customer/agent reads: tests/journeys/inbox.mjs — “two brands deliberately share a team while domains, senders, signatures, customer identities, private knowledge, routing and policy stay isolated, reports aggregate only permitted brands and revocation ends access”. Per-brand/aggregate reports: the same journey plus tests/journeys/reports.mjs — “reports count the workspace calendar cohort with independent median, p90, rate and comment oracles, stream complete formula-safe CSVs above 10,000 rows, and refuse deleted or foreign workspaces” (tests/reports/figures.mjs — “report export journey: independent calendar oracles, complete bounded CSV and transcript export”) for weighted rates. UI configuration, sender, isolated inbox, reports and distinct help-host article routes: tests/journeys/inbox-browser.mjs — “two brands retain their own native configuration, sender, inbox and reports at 1440 and 390 with explicit shared-team report selection”. | Live qualification gap: Two real brand domains/senders with authorized shared-team operation and channel receipt remain unobserved; separate synthetic workspaces do not establish multi-brand qualification. |
ACCESS-001 | Enterprise identity and custom permissions | target | partial | Local implementation/fixture evidence: src/modules/access/; src/platform/auth.ts; src/modules/integrations/inbound-authority.ts; src/edition/delegation/common.ts; src/modules/tickets/model.ts; tests/journeys/identity.mjs; tests/helpers/inbox/ticket-lifecycle.mjs. Native owner/admin/agent, collaborator (notes and follow only) and restricted custom roles exist, with audited refusals and retained owner recovery. Connected-application article read/update/publish scopes are rechecked against the approving member's current role on each request (src/edition/delegation/common.ts lines 20-22); ticket fields carry read/write roles including custom roles. Published help retains its audience gates so a reader never gains internal articles through it. | Implementation/acceptance gaps: knowledge.read and optional per-role knowledgeArticleIds select internal articles independently of edit/publication. tests/helpers/identity/roles-audit.mjs, rolesAuditJourney (registered in tests/journeys/identity.mjs), asserts selected native lists/search/history/translations and connected-grant evidence, refusal outside the current role selection, no edit/publication, next-request permission/selection revocation and security-log access/refusal/revocation entries. Migration 251 persists the role selection; omitted selections retain workspace-wide compatibility, while an empty selection reads no articles. Internal source/dataset management remains separately gated; published help keeps audience gates. Exact-SHA Verify remains required. SSO (SAML/OIDC), SCIM and brand/team permissions remain absent. Live qualification gap: Real Google Workspace, Microsoft Entra ID or Okta SSO/SCIM provisioning/deprovisioning remains unobserved; native-role and connected-grant fixtures do not qualify an identity provider. |
IDENTITY-003 | Two-factor authentication for native accounts | target | done | src/modules/identity/two-factor/; src/platform/auth.ts; src/edition/delegation/consent.ts; tests/journeys/identity.mjs; tests/journeys/identity-browser.mjs (magic sign-in in 1440 and 390px browsers: neutral request, scanner-safe link, one explicit sign-in and refused replay); tests/journeys/delegation-browser.mjs | Each second-factor answer claims its attempt before it is checked, so parallel guesses stay within the limit. Registering a connected application and approving its access are credential installs and step up. A re-entered password (step-up, password change) claims its attempt the same way. Every factor enrollment, a teammate's password reset link (owner's own factor), a changed sign-in email, and copying or resending an admin or owner invitation step up; the identity invitation door without those rules is removed. Accounts without a second factor may confirm beside the password by a single-use, 15-minute, account-bound email sign-in link; requests are atomically rate-limited and audited, and only the fresh sign-in session gains proof. New email claims install no unknown password or recent proof. Existing credentials remain intact; recent mailbox proof authorizes setting a new password without the old one, so older claim-generated or externally chosen passwords cannot strand an account. Enrolled second factors remain required. Setting a first password on an account without one (every moved-in teammate) and adding, repointing or re-enabling a side-panel plugin step up too. |
MOBILE-001 | Support from a phone | target | partial | Local implementation/fixture evidence: src/ui/dashboard; src/modules/widget; tests/journeys/inbox-browser.mjs; tests/journeys/reports-browser.mjs (at 1440 and 390px a widget rating reaches the operator live and on reload, Reports range and both CSVs include it, and reopening clears the prompt while keeping prior feedback). Responsive web journeys exist at desktop/phone viewports. | Implementation/acceptance gaps: Native iOS/Android apps, mobile push and protected offline work are absent. Live qualification gap: Real iOS/Android devices, push-provider delivery/deep links and offline/revocation/cache behavior are unobserved; 1440/390 browser fixtures do not qualify native mobile behavior. |
OUTCOMES-002 | CSAT across support channels | target | partial | Local implementation/fixture evidence: tests/helpers/csat-journey.mjs, csatJourney: eligible signed email response, rerating/concurrency, timing, expiry/revocation, opt-out, cycle history, import/machine exclusions and erasure. tests/helpers/customer-portal-journey.mjs, customerPortalJourney: the same eligible signed invitation in the portal. tests/reports/ratings.mjs (visitor rating lifecycle: current session and cycle, bounded changes, commit races and erasure): widget scale/locale/timing snapshots, latest-cycle rerating and visitor-owned opt-out. Explicit optional customer recovery is stored independently of the rating, and low feedback never changes ticket status. tests/journeys/reports-browser.mjs (at 1440 and 390px a widget rating reaches the operator live and on reload, Reports range and both CSVs include it, and reopening clears the prompt while keeping prior feedback): Settings persistence and Spanish feedback at 1440/390. | Implementation/acceptance and live qualification gaps: Native permitted messaging-channel transports, identity/consent/window/template rules and survey dispatch/response remain incomplete. Live mail and messaging-provider delivery receipts remain pending. Browser qualification passed at 1440/390. |
REPORTS-002 | Workload, service and agent outcomes | target | partial | Local implementation/fixture evidence: tests/reports/team-journey.mjs, teamReportsJourney: known public multichannel/reassignment/reopen/SLA cohort, six dimensions including account, samples/denominators and manual/scheduled CSV; timerCustody: current-role handle-time ownership and adjustment. tests/reports/figures.mjs (report export journey: independent calendar oracles, complete bounded CSV and transcript export; workspace deletion journey: retained links, invitations and commit races never restore report authority), workspace calendar cohort: complete formula-safe export and timezone/exclusions. tests/reports/ratings.mjs (visitor rating lifecycle: current session and cycle, bounded changes, commit races and erasure): current-cycle customer feedback. Explicit customer-confirmed recovery is independent of satisfaction, with reopened/erased cycles unknown. tests/journeys/reports-browser.mjs (at 1440 and 390px a widget rating reaches the operator live and on reload, Reports range and both CSVs include it, and reopening clears the prompt while keeping prior feedback): six dimensions, recovery, saved Settings and downloads at 1440/390. | Implementation/acceptance and live qualification gaps: Handle time by agent, form and intent is asserted by tests/reports/team-journey.mjs, teamReportsJourney, using independent historical form/intent cohorts, duration/session counts and unattributed work reconciled with the total; exact-SHA Verify remains required. Native procedure-version attribution/execution and the complete procedure-attributed cohort remain missing. AI containment and independently observed recovery remain unproved; customer confirmation is labeled separately. Real scheduled-mail receipt and production channel cohorts remain unobserved. Browser qualification passed at 1440/390. |
AGENT-001 | A production support agent with clean handoff | target | partial | Local implementation/fixture evidence: src/modules/ai-support/service.ts; src/modules/knowledge; src/edition/delegation/routes.ts; tests/journeys/first-run.mjs; tests/journeys/delegation.mjs. Configured AI and scoped local handoff are implemented; local first-run/delegation journeys assert configured-provider boundaries and authorized handoff behavior with fixtures. | Implementation/acceptance gaps: Full multichannel, business-action and production-quality coverage is incomplete. Live qualification gap: Representative real-model channel evaluations, restricted retrieval/actions, mid-tool handoff and production-quality outcomes remain unobserved; fixture answers and local handoff do not establish a production support agent. Answering by a live model on an independently installed website/domain remains unobserved; P3 uses a provider-edge fake. |
PROCEDURE-001 | Natural-language procedures and release simulation | target | partial | Local evidence: tests/helpers/ai/procedures.mjs, proceduresJourney, through tests/journeys/ai.mjs: immutable numbered drafts restricted to existing read-only tool names, frozen required synthetic allowed, denied, timeout and injection cases, exact version-linked outputs and sandbox read receipts, current admin authority, isolation from customer messages and mail, failed or mismatched release refusal and no automatic replay of uncertain provider work. tests/helpers/ai/procedures-browser.mjs, proceduresBrowserJourney, through tests/journeys/ai-browser.mjs: create two versions, inspect passing and failing cases and refuse a failed release; retain keyboard focus and visible action results, distinguish loading and failed reads from editable drafts, and hide the form from denied roles, including a narrowed admin. Receipts present readable outcomes and setup guidance, with stopped cases marked not run; browser proof at 1440 and 390. Qualification records an audited simulation result and enables no production execution. | Implementation and acceptance gaps: Controlled production rollout, conversation attribution, revocation and rollback remain absent. Synthetic sandbox tools mirror read-only retrieval names against an isolated fixed publication; integration with real knowledge versions and live data requirements remains unimplemented. Historical examples are not admitted. Initial mode approved with ct riders (27 October): owner or admin with settings permission only, explicit synthetic-only confirmation, no historical customer text transfer and no real actions. This initial mode does not complete the clause or replace contracted historical replay, versioned operational context or controlled production release; all three remain gaps. Live qualification gap: Real-model tool execution in an approved bounded cohort with version-linked conversation results and rollback remains unobserved; synthetic model-edge fixtures do not qualify production procedures. |
AGENT-002 | Inspectable quality and resolution economics | target | partial | Local fixture evidence: tests/journeys/ai.mjs with tests/helpers/ai/answers.mjs (answersJourney) proves the conversation trace joins source publication versions and assistant fingerprint, requested scope, automatic policy approval, timing, provider completion, committed message evidence, denied citations and handoff receipts; it denies visitors and other projects and omits prompt, answer and raw tool payloads. tests/helpers/ai/assistance.mjs (assistanceJourney) proves explicit operator-request attribution, suggestion scope and two-round token evidence without claiming a sent answer. tests/helpers/ai/lifecycle.mjs (lifecycleJourney) proves timeout and interrupted outcomes remain unknown without replay and missing prices remain unavailable. tests/journeys/ai-browser.mjs with tests/helpers/ai/suggestions-browser.mjs (suggestionsAtWidth) opens the trace from a fixture conversation and keyboard-expands timeout and denied details; screenshots cover 1440 and 390. Existing training and usage evidence: src/edition/ai/training-trace.ts; tests/journeys/first-run.mjs; tests/reports/figures.mjs. | Implementation gaps: Procedure report drill-down, joined negative CSAT and reopened outcomes, procedure evaluation coverage, known-denominator rates and reconciled USD cost estimates remain incomplete. The trace shows the latest 50 executions; approval describes the recorded automatic assistant policy or explicit operator request, not a separate per-tool human consent receipt. Provider cost remains unavailable without reconciled price evidence. Live qualification gap: Actual production traces, tool and procedure outcomes and costs reconciled to real usage and prices remain unobserved; network-edge fixtures establish no live economics. |
FEEDBACK-001 | Source-linked feedback and release follow-up | target | missing | No implementation located. No Penny/Vector feedback and shipped-feature support follow-up implementation located. | |
ERASURE-001 | Customer erasure with coherent history | target | done | src/modules/management/contact-erasure.ts; src/modules/management/contact-erasure/providers.ts; tests/journeys/erasure.mjs; tests/journeys/erasure-browser.mjs (at 1440 and 390px an owner erases a contact only after typing ERASE; identity, content and attachment are gone, the session is revoked and other visitors are untouched) | |
AUDIT-001 | Security and accountable actions | target | done | src/modules/audit/; migrations/180_account_security.sql; tests/journeys/identity.mjs; tests/journeys/erasure.mjs; tests/journeys/identity-browser.mjs (magic sign-in in 1440 and 390px browsers: neutral request, scanner-safe link, one explicit sign-in and refused replay) | |
PORTABILITY-001 | Complete customer-owned portable support data | target | done | Population, versioned schema/digest, explicit exclusions, atomic corrupt/oversized/nonempty/schema refusals, owner identity and erasure replay fences: tests/helpers/installer/fresh-install.mjs, freshInstallJourney, through tests/journeys/installer-nightly.mjs. Every portable D1 row and R2 byte/metadata: tests/helpers/rer-archive.mjs, archiveSnapshot/compareArchive, in that journey. Public business-store fixtures: tests/helpers/rer-data.mjs, seedPortableData/verifyPortableData, and tests/helpers/business-portable.mjs, seedPortableBusiness/verifyPortableBusiness, plus tests/helpers/campaigns-portable.mjs, seedPortableCampaign/verifyPortableCampaign: populated campaign settings, consented visits/impressions and reporting survive with campaigns disabled and original retention timestamps. Business stores include reviewed identity associations, companies, knowledge versions, macros, fields, groups, views, workflows, outcomes and evaluations. Source destruction and clean independent checkout: tests/helpers/installer/readme-restore.mjs, readmeRestoreJourney, including native owner entry at 1440/390, revoked old grants and exact archive equality. Durable Object business history is losslessly reconstructed from D1; freshInstallJourney checks the declared native snapshots. Actual interrupted execution states and retained usage: tests/helpers/unfinished-portable.mjs, interruptPortableWork/verifyPortableWork; tests/helpers/training-portable.mjs, verifyPortableTraining. Historical ledger custody: tests/helpers/platform-archive.mjs, platformArchiveJourney. Hosted public command refusals/private custody: tests/helpers/installer/hosted-export.mjs, hostedExportJourney. Held staging public rer export, full content equality and confirmed D1/R2 source deletion: fleet logs/hh-camp-movein-r4-hosted.log (source 19fcf6e5d01e06b86ff706422ce48b98107010f8). Clean current native public import compared all 267 source tables directly and all 24 R2 byte streams/metadata, retaining inert stored states: fleet logs/hh-camp-movein-r4-hosted-restore.log, remote job 20261023T222829785287Z-heavy-slot-78d46af1 at 6379d7b00ef5ab16c49059a26cc347b6a265f704; its full freshInstallJourney also passed. Boundary: the separate Base-data equivalence hold is not closed by this clause. | |
ASSURANCE-001 | Qualified regulated support deployments | target | missing | No implementation located. No regulated-deployment agreement/control qualification flow or compliance acceptance located. | |
PUSH-001 | Reproduce, repair and prove customer recovery | push-further | partial | Local implementation/fixture evidence: src/modules/local-computer/results.ts; src/edition/delegation/routes.ts; tests/journeys/delegation.mjs; tests/helpers/delegation-journey/case.mjs. Approved local repair, distinct readback and human Send are exercised by the delegation edge fixture. | Implementation/acceptance gaps: Sustained customer recovery verification, later recurrence and reopening remain incomplete. Live qualification gap: Repair and independent observation of an authorized real customer product/workspace remain unobserved; edge-fixture readback and sent reports do not establish live customer recovery. |
PUSH-002 | Promises survive every handoff | push-further | missing | No implementation located: obligation records with owner and due time, reminders and follow-up drafts are absent (durable messages and notes in src/modules/conversations/admission.ts are not obligations). | |
PUSH-003 | Learn from reopenings under human control | push-further | missing | No implementation located: version-joined diagnosis of reopened cases, proposals and controlled rollout are absent (evaluation runs in src/modules/training-runs/runner.ts are generic). | |
PUSH-004 | Turn verified edge cases into reviewed knowledge | push-further | missing | No implementation located: gap clustering from unanswered cases, sourced draft articles and recovery measurement are absent (article authoring in src/modules/knowledge/authoring.ts is manual). |
2026-10-28 — Contract structure and retained judgements
Judged from the code and tests at commit 82de9ed83c8d4f0b75c378fdd3e234015dc5fd5b (22 October 2026). R5 additionally updates SLA-001, AUTOMATION-001/002, QUEUE-001/004 and STATUS-001 from the workflow, inbox and packaged recovery journeys on 17 October 2026. WIDGET-001 and AUTOMATION-002 are re-judged at 473a30dab0c6458e5250a55cbebeef999e1e3063 (22 October 2026), with workspace presence and the away-reply correction (migrations 240 and 241). AUTOMATION-001 is re-judged DONE at c36c8cf01a3b8770427e78bed07d71159a0fb872 (23 October 2026).
Original acceptance evidence remains in docs/verify.md. Existing production cutover and Knowledge scope decisions are unchanged; HappyToHelp still lands only through its hh handoff lander after independent cleanup PASS and guarded receipts.
2026-10-28 — Native reply-attachment qualification
This round qualifies native reply-attachment refusal and recovery; it adds no live-provider or full accessibility qualification.