@zackbart/connecta 0.32.0 → 0.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/CHANGELOG.md +98 -0
  2. package/README.md +95 -116
  3. package/SECURITY.md +1 -1
  4. package/bin/connecta.mjs +24 -6
  5. package/bin/version.mjs +1 -1
  6. package/dist/access-tokens.d.ts +167 -23
  7. package/dist/access-tokens.js +676 -140
  8. package/dist/activity.d.ts +3 -0
  9. package/dist/agent-identity.js +47 -0
  10. package/dist/auth/cloudflare-access.js +13 -5
  11. package/dist/branding.d.ts +7 -0
  12. package/dist/branding.js +76 -9
  13. package/dist/call-admission-context.js +15 -0
  14. package/dist/call-admission.js +30 -43
  15. package/dist/call-recovery.js +6 -2
  16. package/dist/catalog-service.js +15 -1
  17. package/dist/config-value-sources.js +16 -9
  18. package/dist/config.d.ts +48 -75
  19. package/dist/config.js +144 -36
  20. package/dist/connector-access.d.ts +4 -34
  21. package/dist/connector-access.js +15 -99
  22. package/dist/connector-caller.d.ts +7 -1
  23. package/dist/connector-caller.js +4 -2
  24. package/dist/connectors/api-connector.d.ts +27 -4
  25. package/dist/connectors/api-connector.js +2 -0
  26. package/dist/connectors/remote-mcp.js +2 -0
  27. package/dist/describe-config.d.ts +31 -7
  28. package/dist/describe-config.js +8 -17
  29. package/dist/execute.js +1 -11
  30. package/dist/fix-prompt.js +2 -2
  31. package/dist/index.d.ts +4 -3
  32. package/dist/index.js +30 -10
  33. package/dist/invocation.js +5 -3
  34. package/dist/membership.d.ts +53 -0
  35. package/dist/membership.js +121 -0
  36. package/dist/module-contracts.d.ts +23 -6
  37. package/dist/oauth-callback-outcome.js +2 -2
  38. package/dist/operator-record.d.ts +2 -2
  39. package/dist/operator-record.js +2 -4
  40. package/dist/operator-ui/agents.d.ts +74 -0
  41. package/dist/operator-ui/agents.js +104 -0
  42. package/dist/operator-ui/config-summary.js +562 -0
  43. package/dist/operator-ui/connection-map.js +375 -0
  44. package/dist/operator-ui/contract.d.ts +149 -28
  45. package/dist/operator-ui/endpoints.js +221 -0
  46. package/dist/operator-ui/fix-prompts.js +5 -5
  47. package/dist/operator-ui/generated.js +5 -4
  48. package/dist/operator-ui/member-page.js +97 -0
  49. package/dist/operator-ui/model.d.ts +14 -6
  50. package/dist/operator-ui/overview.js +134 -0
  51. package/dist/operator-ui/view.d.ts +107 -37
  52. package/dist/operator-ui/view.js +163 -86
  53. package/dist/page-styles.js +5 -3
  54. package/dist/provider.d.ts +61 -8
  55. package/dist/provider.js +46 -7
  56. package/dist/providers/_shared/google/workspace.d.ts +56 -17
  57. package/dist/providers/_shared/google/workspace.js +34 -8
  58. package/dist/providers/_shared/rest/tools.js +2 -2
  59. package/dist/providers/_shared/rest/value-safety.d.ts +50 -0
  60. package/dist/providers/_shared/rest/value-safety.js +699 -7
  61. package/dist/providers/ccb/index.js +2 -2
  62. package/dist/providers/cloudflare/index.js +3 -3
  63. package/dist/providers/cloudflare/rest.js +25 -3
  64. package/dist/providers/cloudflare/skill.generated.js +1 -1
  65. package/dist/providers/cloudflare/value-safety.js +32 -0
  66. package/dist/providers/docs/index.js +4 -4
  67. package/dist/providers/docs/skill.generated.js +2 -2
  68. package/dist/providers/drive/index.js +4 -4
  69. package/dist/providers/drive/skill.generated.js +2 -2
  70. package/dist/providers/forms/index.js +4 -4
  71. package/dist/providers/forms/skill.generated.js +2 -2
  72. package/dist/providers/gmail/index.js +11 -9
  73. package/dist/providers/gmail/skill.generated.js +2 -2
  74. package/dist/providers/mixpanel/index.js +1 -1
  75. package/dist/providers/mixpanel/skill.generated.js +3 -3
  76. package/dist/providers/notion/index.d.ts +7 -0
  77. package/dist/providers/notion/index.js +100 -11
  78. package/dist/providers/notion/rest.js +45 -5
  79. package/dist/providers/notion/skill.generated.js +2 -2
  80. package/dist/providers/notion/value-safety.js +30 -5
  81. package/dist/providers/overflow/index.js +2 -2
  82. package/dist/providers/overflow/skill.generated.js +2 -2
  83. package/dist/providers/planning-center/index.js +2 -2
  84. package/dist/providers/planning-center/skill.generated.js +4 -4
  85. package/dist/providers/revenuecat/skill.generated.js +2 -2
  86. package/dist/providers/sheets/index.d.ts +3 -0
  87. package/dist/providers/sheets/index.js +7 -4
  88. package/dist/providers/sheets/skill.generated.js +2 -2
  89. package/dist/providers/slides/index.js +4 -4
  90. package/dist/providers/slides/skill.generated.js +2 -2
  91. package/dist/providers/stripe/rest.js +9 -2
  92. package/dist/providers/stripe/skill.generated.js +1 -1
  93. package/dist/providers/stripe/value-safety.js +22 -0
  94. package/dist/providers/tithely/index.js +1 -1
  95. package/dist/providers/vercel/index.js +1 -1
  96. package/dist/providers/vercel/rest.js +20 -2
  97. package/dist/providers/vercel/skill.generated.js +2 -2
  98. package/dist/providers/vercel/value-safety.js +22 -0
  99. package/dist/registry.d.ts +2 -3
  100. package/dist/registry.js +23 -9
  101. package/dist/routes/access-tokens.js +82 -75
  102. package/dist/routes/activity-disclosure.js +17 -18
  103. package/dist/routes/activity.js +34 -54
  104. package/dist/routes/actor-labels.js +33 -4
  105. package/dist/routes/agent-path.js +43 -0
  106. package/dist/routes/connect.js +16 -12
  107. package/dist/routes/credentials.js +16 -40
  108. package/dist/routes/mcp.js +161 -104
  109. package/dist/routes/oauth-management.js +11 -5
  110. package/dist/routes/oauth.js +5 -11
  111. package/dist/routes/operator.js +24 -23
  112. package/dist/routes/shared.d.ts +60 -20
  113. package/dist/routes/shared.js +187 -96
  114. package/dist/routes/ui-config.js +437 -97
  115. package/dist/routes/ui-data.js +2 -2
  116. package/dist/routes/ui.js +9 -16
  117. package/dist/runtime/call-admission.js +9 -0
  118. package/dist/server.js +5 -0
  119. package/dist/skills.js +10 -0
  120. package/dist/storage/keys.js +9 -1
  121. package/dist/storage/sql.js +5 -1
  122. package/dist/types.d.ts +29 -7
  123. package/dist/ui.d.ts +1 -1
  124. package/dist/ui.js +23 -16
  125. package/dist/usage-guide.js +1 -1
  126. package/dist/version.d.ts +1 -1
  127. package/dist/version.js +1 -1
  128. package/dist/workspace-address.js +9 -0
  129. package/dist/workspace-subject.js +23 -0
  130. package/documentation/README.md +47 -23
  131. package/documentation/architecture.md +371 -61
  132. package/documentation/auth.md +897 -249
  133. package/documentation/code-mode.md +37 -16
  134. package/documentation/deploying.md +126 -25
  135. package/documentation/integrating.md +97 -23
  136. package/documentation/meta-tools.md +50 -31
  137. package/documentation/migration-0.33.md +352 -0
  138. package/documentation/migration-0.34.md +67 -0
  139. package/documentation/operating.md +3 -1
  140. package/documentation/operator-tests.md +147 -34
  141. package/documentation/operator-ui.md +519 -64
  142. package/documentation/provider-auth-migration.md +37 -23
  143. package/documentation/provider-migration-0.29.md +2 -2
  144. package/examples/worker/AGENTS.md +37 -9
  145. package/examples/worker/README.md +127 -61
  146. package/examples/worker/src/connecta.config.ts +40 -23
  147. package/examples/worker/wrangler.jsonc +4 -1
  148. package/package.json +19 -18
  149. package/templates/node/.env.example +3 -0
  150. package/templates/node/AGENTS.md +33 -6
  151. package/templates/node/Dockerfile +2 -2
  152. package/templates/node/README.md +80 -52
  153. package/templates/node/docker-compose.yml +3 -2
  154. package/templates/node/package.json +4 -3
  155. package/templates/node/src/adopt-token.ts +23 -0
  156. package/templates/node/src/connecta.config.ts +28 -12
  157. package/templates/node/src/rotate-token.ts +17 -0
  158. package/templates/node/src/provision-token.ts +0 -17
@@ -1,20 +1,44 @@
1
1
  # Operator UI tests
2
2
 
3
+ ## Contributor reference
4
+
5
+ This guide describes Connecta implementation and repository verification.
6
+ It is optional for deployment operators. Start with the
7
+ [operator task index](./README.md#operator-tasks) for package-local procedures.
8
+
3
9
  Use this repository-maintenance guide when changing operator pages, data routes,
4
10
  or browser evidence. Read the [operator UI contract](./operator-ui.md) first.
5
11
  [The agent index](./README.md) routes deployment and endpoint tasks.
6
12
 
7
- `test/fixtures/operator-visual.ts` owns the visual data. It builds the config,
8
- live overlay, viewer, and legacy auth details through the current server routes,
9
- using the types in `src/operator-ui/contract.ts` and `model.ts`. Collections use
10
- their corresponding browser types. `test/operator-visual-fixtures.test.ts`
11
- validates contract versions, connector IDs, granted tools, classification,
12
- permissions, provenance, and secret exclusion on Node and Workers. A fixture's
13
- config cannot silently become a stale copy of the server serializer.
13
+ `test/fixtures/operator-visual.ts` owns the visual data. It builds the
14
+ maintainer's contract v2, live overlay, and legacy auth details through the
15
+ current server routes, using the types in `src/operator-ui/contract.ts` and
16
+ `model.ts`; its people carry labels from a fake directory. It sets a few
17
+ limits, an activity retention, one classification override and a GitHub call
18
+ admission rule in code, so Settings and the connector Configuration card show
19
+ set values beside defaults; Slack describes OAuth facts (scope, endpoints, an
20
+ API origin, client secret, PKCE) for the card's auth row. Its Tokens agents
21
+ (`claude-desktop` issued, `triage` none, `nightly` revoked) are real slots
22
+ committed through the deployment's own store, so the contract's `agents` and
23
+ `GET /ui/access-tokens` agree, revisions included; only their timestamps and
24
+ last seen are fixed. The restricted state is the member fixture from
25
+ `test/fixtures/operator-contract-v2.ts`, and the endpoint and matrix variants
26
+ use its maintainer fixture, which covers every runs-as kind and agent pools,
27
+ with `test/fixtures/operator-console.ts` crowding the team pool so its avatar
28
+ stack collapses to "+3".
29
+ Collections use their corresponding browser types.
30
+ `test/operator-visual-fixtures.test.ts` validates contract versions, connector
31
+ IDs, granted tools, matrix cells, classification, provenance, and secret
32
+ exclusion on Node and Workers, and runs `expectMemberViewWithholds` on the
33
+ member body. A fixture's config cannot silently become a stale copy of the
34
+ server serializer.
14
35
 
15
36
  `test/browser/operator-visual.spec.ts` intercepts API reads and serves the real
16
37
  hashed assets and HTML with the production CSP. Loading responses wait on an
17
- explicit gate. Error responses use fixed HTTP failures. Screenshots use a fixed
38
+ explicit gate. Error responses use fixed HTTP failures. The map trace focuses its
39
+ node instead of hovering it: the capture scrolls to the top first, which would
40
+ move the node out from under a pointer and drop the highlight, so the test waits
41
+ for `.map-svg.tracing` before capturing. Screenshots use a fixed
18
42
  clock, UTC, en-US, locally hosted fonts, disabled animations, hidden carets,
19
43
  and a 1280 × 900 viewport. Narrow fixtures use 390 × 844. Every test waits for
20
44
  its state and fonts before capturing.
@@ -22,30 +46,97 @@ its state and fonts before capturing.
22
46
  ## Page and state matrix
23
47
 
24
48
  Each row runs empty, loading, error, populated, and restricted-viewer fixtures
25
- in both light and dark themes, for 120 screenshots.
26
-
27
- | Page or tab | Empty state | Loading/error request | Restricted viewer |
28
- | --------------------- | ------------------------------------ | --------------------- | --------------------------------------------------- |
29
- | Overview | No connectors or attention items | Config | Scoped connectors, no privileged navigation |
30
- | Connectors | No connectors | Config | Read grant and credential slot, no other connectors |
31
- | Connector Config | Zero-tool connector | Config | Scoped connector snapshot |
32
- | Connector Tools | Empty catalog | Config | Read tool only |
33
- | Connector Auth | Deployment-managed auth | Config | Visible slot, deployment-managed auth |
34
- | Connector Activity | No calls | Activity | Unavailable |
35
- | Connector Diagnostics | No observed drift/call | Config | Scoped diagnostics |
36
- | Tools | Empty catalog | Config | Read tool only |
37
- | Access | No pools or client tokens | Config | No token management |
38
- | Access tokens | No client tokens | Token list | No token management |
39
- | Activity | No calls | Activity | Unavailable |
40
- | Config | Snapshot without connectors or pools | Config | Scoped snapshot |
41
-
42
- Another 36 screenshots cover configured, mismatched, unreadable and multifield
49
+ in both light and dark themes, for 90 screenshots. The restricted viewer is a
50
+ pool member, who gets the member page, with no tabs, on every path.
51
+
52
+ | Page or tab | Empty state | Loading/error request | Restricted viewer (member) |
53
+ | -------------------- | ------------------------------------ | --------------------- | ----------------------------------- |
54
+ | Overview | No connectors: nothing to map | Config | Member page at `/` |
55
+ | Endpoints | Root endpoint without tools | Config | Member page: endpoints, accounts |
56
+ | Connectors | No connectors | Config | Member page, no connector request |
57
+ | Connector Tools | Empty catalog | Config | Member page, no connector request |
58
+ | Connector Connection | Deployment-managed auth | Config | Member page, no connector request |
59
+ | Connector Activity | No calls | Activity | Member page, no activity request |
60
+ | Tokens | No declared agents | Token list | Member page, no token request |
61
+ | Activity | No calls | Activity | Member page, no activity request |
62
+ | Settings | Snapshot without connectors or pools | Config | Member page, no configuration facts |
63
+
64
+ Populated Overview has a failing connector, drift, auth and credential problems
65
+ and a tokenless agent in its attention list. Populated Endpoints shows who can use each endpoint; populated Tokens has one
66
+ agent per slot state, with pools and last seen.
67
+
68
+ Another 60 screenshots cover the Overview map on the frozen v2 maintainer, one
69
+ person's trace, and the narrow map list; configured, mismatched, unreadable and multifield
43
70
  credentials; all three OAuth client mechanisms; clean and unobserved drift;
44
- historical Activity; client setup; schema dialog; read/write filters; expanded
45
- config provenance; narrow sign-in and Auth; and deployment branding. The base
71
+ historical Activity; client setup; schema dialog; read/write filters; narrow
72
+ Settings; narrow sign-in and Connection; deployment branding; `/mcp`
73
+ and an agent pool expanded with every runs-as kind; command search; narrow
74
+ endpoints; the connector × endpoint matrix, one cell's open popover, and the
75
+ narrow matrix; a new token's one-time secret dialog; and the member page, wide
76
+ and narrow. `endpoints-expanded` and `narrow-endpoints` include the team row
77
+ collapsed to "+3". The base
46
78
  populated Activity fixture includes grouped calls, an ungrouped legacy row,
47
79
  classification/result size/client facts, and a catalog-change event.
48
80
 
81
+ `test/browser/operator-matrix.spec.ts` serves the frozen v2 fixtures to the
82
+ real shell. It covers the matrix's table semantics, cell names, status dots,
83
+ runs-as labels in each kind's popover, popover keyboard behavior, placement at a short viewport, the in-flow
84
+ fallback without CSS anchors, and the absence of `style` attributes, agent URLs on Endpoints, the member page (its
85
+ received body checked with `expectMemberViewWithholds`, `/ui/data` answering 404
86
+ and never requested, no maintainer fact rendered, no maintainer request sent),
87
+ the 401 sign-in and 404 no-access gates on `/ui/api/config` with no maintainer
88
+ navigation, the shared recovery banner on Tokens and Activity through a failed
89
+ refresh that stalls past its deadline (one focusable Retry, no maintainer
90
+ request until Retry succeeds), an open client setup drawer closed by a failed
91
+ refresh with focus on Retry, Tokens under recovery (an open rotate question
92
+ closes with focus on Retry and nothing sent; an unseen secret dialog stays open
93
+ over the banner until dismissed), payload sentinels, CSP, and the refusal of a v1 body. Matrix coverage excludes retired grants from
94
+ its live counts and pie, keeps their names inspectable in the popover, and
95
+ renders an unavailable catalog as a dashed empty ring with "?" and an unknown
96
+ accessible name. Cell names distinguish equal grants against different live
97
+ catalog sizes. `test/operator-endpoints.test.ts` covers those view-model cases,
98
+ including a known empty catalog versus an unavailable one.
99
+ `test/operator-connection-map.test.ts` also checks that a failed or unobserved
100
+ catalog counts no tools, which the map draws as a muted dash, while a known
101
+ empty catalog counts zero.
102
+ `test/browser/operator-overview.spec.ts` covers the Overview on the frozen v2
103
+ fixtures: the status pill, stat labels and numbers, map columns, dashed read-only grants and dotted
104
+ tokenless access; attention rows with their fix links, a copied fix prompt equal
105
+ to the catalogue's text and a failing connector sorted first; the hover
106
+ sentence replacing the legend, and dimming; keyboard focus in column order with each node's sentence
107
+ as its accessible name, Enter opening an endpoint's row and a connector; the
108
+ narrow list, whose caller chips link where their map nodes do; an empty deployment; and a member at `/` getting the member page
109
+ with no maintainer read, plus CSP and no `style` attributes.
110
+ `test/browser/operator-console.spec.ts` covers UI-3: who-can-use chips by
111
+ label, raw id and agent mark and "+N" from the keyboard; Tokens rows,
112
+ issue with the once-only secret dialog, in-row rotate and revoke questions,
113
+ 503, 499 and 409 failures that send exactly one request, slots missing from
114
+ the list or left unresolved shown with disabled controls until Refresh; and the
115
+ member page (its received body checked with `expectMemberViewWithholds`, no
116
+ tabs, Search or maintainer fact, OAuth Connect, Reconnect and Disconnect sent as
117
+ `?mode=continue`, `?mode=restart` and `DELETE`, the credential `actions`
118
+ shapes, a refresh that drops an action closing its confirmation, a failed or
119
+ stalled refresh keeping member chrome with Retry, a consent that outlasts the
120
+ OAuth poll window), plus keyboard, sentinels, CSP and no `style` attributes.
121
+ `test/operator-console.test.ts` covers the chip, slot-row and member-page view
122
+ models. `test/browser/operator-scheme.spec.ts` holds the main bundle and checks the
123
+ first painted background: saved dark on a light system paints dark, a pinned
124
+ light deployment paints light over saved dark, and throwing storage keeps the
125
+ system scheme while the released bundle settles on the normal bearer gate, and a
126
+ sign-in there raises no error. The real-route token test in `test/browser/operator-ui.spec.ts` serves
127
+ the contract, `/ui/data` and the slot routes from one real v2 deployment and
128
+ checks that each mutation sent a distinct 22-character `expect`.
129
+ `test/operator-store.test.ts` serves `/ui/api/config` from its own mock, so
130
+ each test's data and detail answers stay separate, and covers role changes: a
131
+ maintainer demoted after a failed refresh keeps no maintainer state and sends
132
+ no maintainer request, and a promoted member loads maintainer data fresh. It
133
+ also drives UI-3's slot fence with a session-token read held open: reloads and
134
+ contract refreshes that move or drop a slot before dispatch, late results that
135
+ cannot overwrite newer evidence, unknown and unreadable outcomes that only a
136
+ later list read settles, revisions sent as `expect` and compared with the
137
+ contract, an identity change that leaves the next identity's fence alone, and
138
+ member actions whose `manage` a refresh changes.
139
+
49
140
  Screenshots cover presentation. Keep unit and server tests for INV-6 sentinels,
50
141
  secret disclosure, auth and grant boundaries, CSRF, identity fences, cancellation,
51
142
  request lifetime, and error sanitization. Keep browser tests for keyboard/focus,
@@ -56,15 +147,15 @@ cannot prove these rules.
56
147
 
57
148
  The source of truth is `*-linux.png`, produced on `ubuntu-latest` with the
58
149
  lockfile's Playwright Chromium. Both CI workflows use the same runner, Node 22,
59
- and `npm run test:browser:install -- --with-deps`. macOS runs fixture routing and
150
+ and `pnpm run test:browser:install --with-deps`. macOS runs fixture routing and
60
151
  readiness checks but omits screenshot comparison. The update script refuses
61
152
  non-Linux hosts. Do not commit Darwin baselines.
62
153
 
63
154
  When Docker is unavailable, use the **Operator snapshots** workflow:
64
155
 
65
156
  ```sh
66
- git push --force-with-lease origin feat/p4-ui-tests
67
- gh workflow run operator-snapshots.yml --ref feat/p4-ui-tests
157
+ git push --force-with-lease origin <branch>
158
+ gh workflow run operator-snapshots.yml --ref <branch>
68
159
  # Read the completed run ID from the Actions page or gh run list.
69
160
  gh run download RUN_ID --name operator-linux-snapshots \
70
161
  --dir test/browser/operator-visual.spec.ts-snapshots
@@ -75,9 +166,9 @@ images and changed files, commit the intentional changes, and push again. The
75
166
  normal CI browser job must compare and pass against that commit. Snapshot
76
167
  updates run only through `workflow_dispatch`.
77
168
 
78
- On a matching Linux runner, `npm ci`, install Chromium with the command above,
79
- then run `npm run test:browser:snapshots`. The normal command is
80
- `npm run test:browser`. Missing baselines fail CI; retries cannot bless them.
169
+ On a matching Linux runner, `pnpm install --frozen-lockfile`, install Chromium with the command above,
170
+ then run `pnpm run test:browser:snapshots`. The normal command is
171
+ `pnpm run test:browser`. Missing baselines fail CI; retries cannot bless them.
81
172
  Set `OPERATOR_VISUAL_INSPECT=1` to retain local screenshots under ignored
82
173
  `test-results/` for inspection, without updating committed baselines.
83
174
 
@@ -94,3 +185,25 @@ The flows cover Clerk sign-in/reload/sign-out; OAuth connect/consent/callback/
94
185
  connected reread/reload; and credential save/test/replace/remove. They collect
95
186
  CSP violations across every document and popup, and fail on unexpected network
96
187
  traffic. No credentials enter visual fixtures or screenshot baselines.
188
+
189
+ `test/browser/operator-auth-recovery.spec.ts` serves the production UI and real
190
+ operator routes with a trusted Worker Access context, serving the server's own
191
+ contract v2. Each admission reads the contract first,
192
+ so its read counts include one contract read per admission. It covers transient and
193
+ rejected identity reads, missing shell context, delayed OAuth grant commits,
194
+ catalog/auth reconciliation, and unreadable credential metadata, all without
195
+ reloading the document. The repeated-refusal browser case drives ten focus and visibility returns
196
+ 160 ms apart with a controlled clock, checks the shared backoff and exhausted
197
+ retry budget, then recovers without reloading. Store tests cover the same
198
+ state transitions for 401, 403, and 503 refusals and debounced explicit Retry.
199
+ Delayed config/detail cases in both runtimes and Chromium keep returning focus
200
+ every 2.1 seconds, require eventual catalog/auth publication, and assert one
201
+ recovery cycle. Store cases also preserve explicit Retry and sign-out while
202
+ that cycle is pending. The Retry focus browser case uses a controlled clock to
203
+ check click coalescing inside 150 ms and heading focus after a later Retry.
204
+ Store tests defend bounded recovery and OAuth polling,
205
+ atomic refresh publication, identity cancellation, and late-response fencing.
206
+ Multi-connector browser cases assert scoped polling and cancellation after
207
+ navigation, successful authorization, and failed status. The Clerk browser
208
+ fixture holds sign-out pending to check that queued focus and later passive
209
+ returns cannot restore operator data.