@zackbart/connecta 0.37.1 → 0.39.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 (265) hide show
  1. package/CHANGELOG.md +94 -0
  2. package/README.md +5 -4
  3. package/bin/connecta.mjs +1 -39
  4. package/bin/version.mjs +1 -1
  5. package/dist/access-tokens.js +2 -4
  6. package/dist/agent-identity.js +1 -1
  7. package/dist/agent-routes.js +231 -0
  8. package/dist/auth/clerk-sdk/generated.js +2 -1
  9. package/dist/auth/downstream-oauth/consent.js +519 -0
  10. package/dist/auth/downstream-oauth/grant-store.js +439 -0
  11. package/dist/auth/downstream-oauth/refresh-coordinator.js +562 -0
  12. package/dist/auth/downstream-oauth/refresh-records.js +447 -0
  13. package/dist/auth/downstream-oauth/sdk-hooks.js +242 -0
  14. package/dist/auth/downstream-oauth.js +66 -2516
  15. package/dist/auth/downstream-revocation.js +1 -1
  16. package/dist/auth/native.js +27 -0
  17. package/dist/auth/oauth-grant.js +24 -0
  18. package/dist/auth/oauth-token-response.js +1 -1
  19. package/dist/auth/static-oauth.js +153 -131
  20. package/dist/auth/vercel-agent.js +2 -1
  21. package/dist/auth-elicitation.js +9 -3
  22. package/dist/authorization-handoff.js +11 -5
  23. package/dist/branding.d.ts +1 -15
  24. package/dist/branding.js +2 -2
  25. package/dist/bytes.js +42 -0
  26. package/dist/call-admission-context.js +2 -5
  27. package/dist/call-recovery.js +0 -3
  28. package/dist/catalog-cache.js +130 -43
  29. package/dist/catalog-fingerprint.js +2 -18
  30. package/dist/catalog-policy.js +18 -0
  31. package/dist/catalog-service.js +285 -48
  32. package/dist/catalog.js +18 -2
  33. package/dist/config-defaults.d.ts +1 -0
  34. package/dist/config-defaults.js +1 -0
  35. package/dist/config-schema.d.ts +1 -1
  36. package/dist/config-schema.js +6 -2
  37. package/dist/config.d.ts +57 -25
  38. package/dist/config.js +30 -77
  39. package/dist/connector-caller.d.ts +1 -1
  40. package/dist/connector-health.js +59 -0
  41. package/dist/connector-status.js +117 -0
  42. package/dist/connectors/api-connector.d.ts +7 -2
  43. package/dist/connectors/api-connector.js +11 -7
  44. package/dist/connectors/guarded-fetch.d.ts +0 -6
  45. package/dist/connectors/guarded-fetch.js +1 -11
  46. package/dist/connectors/negotiation-cache.js +22 -4
  47. package/dist/connectors/remote-mcp/call.js +164 -0
  48. package/dist/connectors/remote-mcp/catalog.js +278 -0
  49. package/dist/connectors/remote-mcp/config.js +263 -0
  50. package/dist/connectors/remote-mcp/connection.js +671 -0
  51. package/dist/connectors/remote-mcp/errors.js +488 -0
  52. package/dist/connectors/remote-mcp/oauth.js +469 -0
  53. package/dist/connectors/remote-mcp/resources.js +473 -0
  54. package/dist/connectors/remote-mcp/runtime.js +1 -0
  55. package/dist/connectors/remote-mcp/transport.js +544 -0
  56. package/dist/connectors/remote-mcp.js +61 -2898
  57. package/dist/connectors/resource-uri.js +0 -4
  58. package/dist/credential-contract.d.ts +23 -0
  59. package/dist/credential-reads.js +17 -0
  60. package/dist/credential-verification.js +53 -0
  61. package/dist/credentials.d.ts +7 -0
  62. package/dist/credentials.js +60 -25
  63. package/dist/d1.d.ts +0 -89
  64. package/dist/d1.js +0 -34
  65. package/dist/describe-config.d.ts +12 -2
  66. package/dist/describe-config.js +2 -0
  67. package/dist/discovery-health.js +199 -0
  68. package/dist/downstream-input.js +4 -2
  69. package/dist/errors.d.ts +55 -17
  70. package/dist/errors.js +95 -41
  71. package/dist/execute.js +172 -125
  72. package/dist/executor-result.js +5 -2
  73. package/dist/executors/quickjs-runtime.js +2 -25
  74. package/dist/executors/quickjs.js +1 -1
  75. package/dist/guest-functions.js +83 -0
  76. package/dist/guest-runtime.js +63 -20
  77. package/dist/guest-types.d.ts +24 -10
  78. package/dist/http/argument-problems.js +35 -0
  79. package/dist/http/client.js +1 -1
  80. package/dist/http/errors.js +7 -6
  81. package/dist/http/fields.js +192 -13
  82. package/dist/http/hatch-response.js +73 -0
  83. package/dist/http/hatch.js +88 -23
  84. package/dist/http/json-schema.js +1 -1
  85. package/dist/http/node-transport.js +0 -1
  86. package/dist/http/oauth.js +4 -3
  87. package/dist/http/paging.js +6 -9
  88. package/dist/http/provider.js +33 -5
  89. package/dist/http/safety.js +9 -1
  90. package/dist/http/services.js +1 -8
  91. package/dist/http/tools.js +45 -30
  92. package/dist/http/vendor.js +7 -7
  93. package/dist/identity.js +2 -6
  94. package/dist/index.d.ts +1 -1
  95. package/dist/index.js +9 -2
  96. package/dist/invocation-auth.js +2 -1
  97. package/dist/invocation.js +21 -6
  98. package/dist/membership.d.ts +13 -5
  99. package/dist/membership.js +34 -2
  100. package/dist/meta-tools.js +50 -35
  101. package/dist/native-recovery.js +4 -16
  102. package/dist/native-tools.js +6 -2
  103. package/dist/oauth-handoff.js +2 -2
  104. package/dist/oauth-sealing.js +10 -0
  105. package/dist/operation-vocabulary.js +136 -14
  106. package/dist/operator-record.d.ts +2 -2
  107. package/dist/operator-record.js +2 -49
  108. package/dist/operator-ui/contract.d.ts +12 -2
  109. package/dist/operator-ui/generated.js +3 -3
  110. package/dist/operator-ui/model.d.ts +22 -1
  111. package/dist/program-writes.js +3 -8
  112. package/dist/provider-call.js +0 -7
  113. package/dist/provider.d.ts +1 -1
  114. package/dist/providers/_shared/google/kit.js +1 -6
  115. package/dist/providers/_shared/google/service-account.js +1 -3
  116. package/dist/providers/_shared/google/workspace.d.ts +1 -1
  117. package/dist/providers/_shared/guide.js +3 -0
  118. package/dist/providers/_shared/json.js +12 -0
  119. package/dist/providers/_shared/rest/compact-index.js +1 -1
  120. package/dist/providers/_shared/rest/kit.js +1 -3
  121. package/dist/providers/_shared/rest/operation-index.js +49 -53
  122. package/dist/providers/_shared/rest/value-safety.js +106 -28
  123. package/dist/providers/breeze/api.js +9 -8
  124. package/dist/providers/breeze/index.js +4 -2
  125. package/dist/providers/breeze/skill.generated.js +1 -1
  126. package/dist/providers/breeze/tools.js +7 -7
  127. package/dist/providers/ccb/api.js +3 -7
  128. package/dist/providers/ccb/index.js +7 -1
  129. package/dist/providers/ccb/skill.generated.js +1 -1
  130. package/dist/providers/ccb/tools.js +1 -6
  131. package/dist/providers/cloudflare/api.js +10 -3
  132. package/dist/providers/cloudflare/index.js +2 -1
  133. package/dist/providers/cloudflare/safety.js +3 -3
  134. package/dist/providers/cloudflare/skill.generated.js +1 -1
  135. package/dist/providers/docs/lib/schemas.js +24 -22
  136. package/dist/providers/docs/safety.js +2 -0
  137. package/dist/providers/docs/skill.generated.js +1 -1
  138. package/dist/providers/docs/tools.js +4 -14
  139. package/dist/providers/drive/api.js +1 -0
  140. package/dist/providers/drive/lib/contracts.js +8 -5
  141. package/dist/providers/drive/skill.generated.js +1 -1
  142. package/dist/providers/drive/tools.js +23 -41
  143. package/dist/providers/forms/api.js +1 -0
  144. package/dist/providers/forms/skill.generated.js +1 -1
  145. package/dist/providers/forms/tools.js +11 -16
  146. package/dist/providers/github/api.js +1 -0
  147. package/dist/providers/github/lib/discovery.js +1 -1
  148. package/dist/providers/github/skill.generated.js +1 -1
  149. package/dist/providers/github/tools.js +61 -17
  150. package/dist/providers/gmail/lib/schemas.js +60 -50
  151. package/dist/providers/gmail/skill.generated.js +1 -1
  152. package/dist/providers/gmail/tools.js +12 -26
  153. package/dist/providers/granola/index.js +2 -0
  154. package/dist/providers/granola/skill.generated.js +1 -1
  155. package/dist/providers/overflow/api.js +8 -4
  156. package/dist/providers/overflow/index.js +2 -1
  157. package/dist/providers/overflow/skill.generated.js +1 -1
  158. package/dist/providers/overflow/tools.js +3 -7
  159. package/dist/providers/planning-center/api.js +5 -2
  160. package/dist/providers/planning-center/lib/constants.d.ts +1 -1
  161. package/dist/providers/planning-center/lib/json-api.js +1 -9
  162. package/dist/providers/planning-center/skill.generated.js +1 -1
  163. package/dist/providers/planning-center/tools.js +2 -1
  164. package/dist/providers/quickbooks/safety.js +80 -39
  165. package/dist/providers/quickbooks/skill.generated.js +1 -1
  166. package/dist/providers/sheets/api.js +1 -0
  167. package/dist/providers/sheets/skill.generated.js +1 -1
  168. package/dist/providers/sheets/tools.js +14 -23
  169. package/dist/providers/slides/skill.generated.js +1 -1
  170. package/dist/providers/slides/tools.js +19 -26
  171. package/dist/providers/stripe/index.js +2 -1
  172. package/dist/providers/stripe/safety.js +2 -2
  173. package/dist/providers/stripe/skill.generated.js +1 -1
  174. package/dist/providers/tithely/api.js +5 -8
  175. package/dist/providers/tithely/index.js +3 -2
  176. package/dist/providers/tithely/skill.generated.js +1 -1
  177. package/dist/providers/tithely/tools.js +7 -5
  178. package/dist/providers/vercel/api.js +2 -7
  179. package/dist/providers/vercel/lib/pin.js +1 -1
  180. package/dist/providers/vercel/safety.js +1 -1
  181. package/dist/providers/vercel/skill.generated.js +1 -1
  182. package/dist/providers/vercel/tools.js +6 -4
  183. package/dist/redaction-marker.js +2 -2
  184. package/dist/registry.d.ts +11 -5
  185. package/dist/registry.js +46 -20
  186. package/dist/request-principal.js +1 -1
  187. package/dist/request-state.js +2 -2
  188. package/dist/routes/access-tokens.js +1 -1
  189. package/dist/routes/activity-disclosure.js +1 -1
  190. package/dist/routes/connect.js +2 -2
  191. package/dist/routes/credentials.js +130 -61
  192. package/dist/routes/dispatch.js +5 -1
  193. package/dist/routes/mcp.js +34 -17
  194. package/dist/routes/oauth-management.js +1 -1
  195. package/dist/routes/operator.js +6 -5
  196. package/dist/routes/shared.d.ts +13 -8
  197. package/dist/routes/shared.js +15 -9
  198. package/dist/routes/ui-config.js +3 -3
  199. package/dist/routes/ui-data.js +126 -20
  200. package/dist/routes/ui.js +17 -1
  201. package/dist/runtime/call-admission.js +1 -1
  202. package/dist/runtime/call.js +8 -3
  203. package/dist/runtime/native-storage.js +9 -0
  204. package/dist/runtime/request-reads.js +182 -0
  205. package/dist/runtime/request-scope.js +16 -0
  206. package/dist/runtime/settlement.js +1 -1
  207. package/dist/runtime/shared-read.js +2 -15
  208. package/dist/runtime/storage.js +12 -0
  209. package/dist/sent-secrets.d.ts +1 -2
  210. package/dist/sent-secrets.js +3 -8
  211. package/dist/server.js +4 -4
  212. package/dist/skills.js +44 -54
  213. package/dist/sqlite.d.ts +0 -19
  214. package/dist/sqlite.js +2 -83
  215. package/dist/storage/keys.js +69 -128
  216. package/dist/storage/memory.js +8 -2
  217. package/dist/storage/sql-native.js +27 -101
  218. package/dist/storage/sql.d.ts +1 -24
  219. package/dist/storage/sql.js +13 -14
  220. package/dist/storage-digest.js +32 -0
  221. package/dist/timeout.js +8 -0
  222. package/dist/tool-error.js +4 -0
  223. package/dist/types.d.ts +33 -0
  224. package/dist/url-safety.js +0 -4
  225. package/dist/usage-guide.js +18 -37
  226. package/dist/validate.d.ts +3 -0
  227. package/dist/validate.js +220 -158
  228. package/dist/version.d.ts +1 -1
  229. package/dist/version.js +1 -1
  230. package/dist/worker.js +1 -1
  231. package/dist/write-outcome.js +0 -3
  232. package/documentation/README.md +19 -55
  233. package/documentation/architecture.md +436 -515
  234. package/documentation/auth.md +229 -88
  235. package/documentation/code-mode.md +201 -94
  236. package/documentation/deploying.md +25 -43
  237. package/documentation/integrating.md +18 -19
  238. package/documentation/meta-tools.md +225 -51
  239. package/documentation/migration-0.33.md +10 -6
  240. package/documentation/migration-0.34.md +5 -5
  241. package/documentation/migration-retired-layouts.md +74 -0
  242. package/documentation/operator-tests.md +20 -120
  243. package/documentation/operator-ui.md +108 -16
  244. package/documentation/pool-membership-upgrade.md +44 -0
  245. package/documentation/provider-auth-migration.md +4 -10
  246. package/documentation/provider-migration-0.29.md +4 -15
  247. package/documentation/providers.md +105 -0
  248. package/examples/worker/AGENTS.md +14 -16
  249. package/examples/worker/README.md +24 -118
  250. package/examples/worker/src/connecta.config.ts +1 -0
  251. package/guides/connecting-agents.md +9 -31
  252. package/guides/how-it-works.md +6 -4
  253. package/guides/safety-and-trust.md +4 -1
  254. package/package.json +19 -19
  255. package/templates/node/AGENTS.md +13 -12
  256. package/templates/node/README.md +9 -26
  257. package/templates/node/package.json +1 -1
  258. package/templates/node/src/connecta.config.ts +1 -0
  259. package/dist/auth/oauth-v2-migration.js +0 -135
  260. package/dist/provider-call-facts.d.ts +0 -115
  261. package/dist/provider-call.d.ts +0 -112
  262. package/dist/storage/d1-copy.js +0 -255
  263. package/dist/storage/sql-schema.d.ts +0 -6
  264. package/examples/worker/kv-to-d1.wrangler.jsonc +0 -26
  265. package/examples/worker/scripts/copy-kv-to-d1.mjs +0 -162
@@ -1,8 +1,7 @@
1
1
  # Migration to 0.33
2
2
 
3
- Use this upgrade guide for an existing deployment moving to 0.33.
4
- [Deployment upgrades](./deploying.md#upgrade-an-existing-deployment) cover the
5
- general procedure; [the agent index](./README.md) routes other work.
3
+ Apply the [general upgrade procedure](./deploying.md#upgrade-an-existing-deployment)
4
+ when moving from 0.32 to 0.33.
6
5
 
7
6
  0.33 makes pools the access model.
8
7
  Every deployment with inbound auth changes its configuration. Each removed
@@ -41,6 +40,10 @@ the sections in order, then [verify](#verify).
41
40
  | `DELETE /ui/credentials/<id>` on an empty slot answering 204 | 409 `{ "problem": "credential_required" }` |
42
41
  | The `agent_not_maintainer` denial reason | Removed; agents are refused at human endpoints before admission |
43
42
 
43
+ This guide records the 0.33 migration. Current versions require every pool to
44
+ list only people or only agents. If a 0.33 deployment combined them, follow
45
+ [Split mixed pools](./pool-membership-upgrade.md) as well.
46
+
44
47
  ## Maintainers and pool members
45
48
 
46
49
  0.32 combined an identity resolver, a top-level `grant`, and pool `grant`
@@ -338,8 +341,9 @@ pools: {
338
341
 
339
342
  ## Verify
340
343
 
341
- 1. Start the deployment; construction errors name each removed option's
342
- replacement.
344
+ 1. Start the deployment; 0.33 construction errors name each removed option's
345
+ replacement. Releases after 0.37.1 use generic unknown-option errors;
346
+ use this guide for replacements.
343
347
  2. Sign in as a maintainer and confirm plain `/mcp` and the operator UI work.
344
348
  3. Run `connecta doctor --pool <pool>` with each agent's token, and confirm
345
349
  the same token at `/mcp` is refused.
@@ -349,4 +353,4 @@ pools: {
349
353
  absent: search finds none of their tools and a call fails
350
354
  `unknown_address`. The same holds in any pool without an owner, even one
351
355
  that lists a Workspace connector with a subject mapping.
352
- 6. Confirm each `<agent>-<user>` pool lists no other person in `members`.
356
+ 6. Confirm each `<agent>-<user>` pool lists only the agent in `members` (the current construction rule).
@@ -1,9 +1,7 @@
1
1
  # Migration to 0.34
2
2
 
3
- Use this guide when upgrading an existing deployment from 0.33 to 0.34.
4
- [Deployment upgrades](./deploying.md#upgrade-an-existing-deployment) cover the
5
- general procedure; [the agent index](./README.md) routes other work. Upgrades
6
- from earlier versions must also apply the intervening migrations.
3
+ Apply the [general upgrade procedure](./deploying.md#upgrade-an-existing-deployment)
4
+ when moving from 0.33 to 0.34, including intervening migrations for older versions.
7
5
 
8
6
  No storage migration, token rotation or required configuration field is added.
9
7
  Review the following changes before updating the package pin.
@@ -41,7 +39,9 @@ If an agent needs to act as Alice, put that access in her personal pool and set
41
39
  to use. Confirm the pool's tools and members before adding an owner. Follow
42
40
  [the agent pool layout](./auth.md#organizing-an-agents-pools) for the full
43
41
  configuration. People in the same pool, agents in owned pools and connectors
44
- with a fixed `subject` address keep their behavior.
42
+ with a fixed `subject` address keep their behavior. Current versions also
43
+ require each pool to list only people or only agents; see
44
+ [Split mixed pools](./pool-membership-upgrade.md).
45
45
 
46
46
  ## Optional settings and development tooling
47
47
 
@@ -0,0 +1,74 @@
1
+ # Migrate before past-layout support is removed
2
+
3
+ Use this guide before upgrading to the release that removes the pre-0.29
4
+ storage and OAuth layout migrations. [Deployment upgrades](./deploying.md#upgrade-an-existing-deployment)
5
+ cover the general procedure; [the agent index](./README.md) routes other work.
6
+ Apply intervening configuration and provider migrations too.
7
+
8
+ **0.37.1 is the last bridge release containing these migrations.** A deployment
9
+ with Workers KV, a JSON state file, or OAuth layout-2 grants must first upgrade
10
+ to exactly `@zackbart/connecta@0.37.1` and finish the relevant migrations there.
11
+ Installing the bridge release alone does not migrate unused grants or storage.
12
+ Deployments already using D1 or SQLite with layout-3 grants need no conversion.
13
+ Keep the existing database, connector ids, owner partitions, and vault key.
14
+
15
+ ## Before updating the package pin
16
+
17
+ 1. Back up the source state and destination database securely, including expiry
18
+ metadata, and preserve the credential encryption key. Stop traffic and all
19
+ background writers; drain OAuth callbacks and refreshes. Keep a recoverable
20
+ 0.37.1 deployment and its installed package until verification completes.
21
+ 2. For Workers KV, use 0.37.1's installed
22
+ `examples/worker/scripts/copy-kv-to-d1.mjs` and `kv-to-d1.wrangler.jsonc`.
23
+ Follow that version's `examples/worker/README.md#upgrading-from-028`:
24
+ wait for stable KV, run `--maintenance`, resolve invalid entries and
25
+ conflicts, run `--maintenance --verify`, switch to D1 under maintenance,
26
+ verify, then run `--maintenance --mark-live` before reopening traffic.
27
+ The underlying API is `copyKvToD1(kv, db, { source })` from
28
+ `@zackbart/connecta/d1`; finish every returned cursor, verify hashes and
29
+ expiries, and call `markKvToD1Live(db, source)` before cutover. Never copy
30
+ stale KV over a database that has accepted new writes.
31
+ 3. For Node's pre-SQLite JSON state, stop the server and run the bridge CLI:
32
+
33
+ ```sh
34
+ npx --yes --package=@zackbart/connecta@0.37.1 connecta migrate-state .connecta-state.json .connecta.sqlite
35
+ ```
36
+
37
+ It copies live entries with their expiry, keeps existing destination keys,
38
+ and leaves the JSON file unchanged. The old activity JSONL is not imported.
39
+ Use the destination SQLite file for subsequent starts.
40
+
41
+ 4. While still running 0.37.1 over the SQL destination, open **every OAuth
42
+ grant once, for every connector and owner partition** through its normal
43
+ authorized connection. This includes dormant personal grants. The first
44
+ grant read converts layout 2 to the single layout-3 `oauth:grant` record
45
+ and deletes historical keys. Merely listing configuration is insufficient.
46
+ Grants too old to have issuer binding, invalid ciphertext, and pending
47
+ consents require fresh authorization on the bridge release.
48
+ 5. Verify each existing OAuth connection, vault credential and agent token,
49
+ including every personal owner. Confirm layout-3 grant records and no
50
+ pending layout-2 cleanup using trusted storage tooling without printing
51
+ credential bodies. Only then upgrade the package pin to the removing release.
52
+
53
+ ## Removed interfaces and stale state
54
+
55
+ | Removed path | Behavior after upgrading | Recovery |
56
+ | ---------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
57
+ | OAuth layout-2 reader and cleanup | An owner with only old keys has no usable grant. Reads return absent, credentials are never opened or copied, and a warning says to authorize again or migrate on 0.37.1. Calls require consent. Old keys remain untouched. Existing layout-3 grants, including those with an obsolete cleanup marker, remain readable. | Connect again. To preserve an old grant instead, restore a consistent pre-upgrade backup and run the bridge procedure. |
58
+ | `copyKvToD1`, `markKvToD1Live`, their types/error, and copy script/config | Named imports fail; no KV copy runs. A KV adapter without atomic compare-and-set is refused at construction. A fresh D1 database contains none of the old credentials or tokens. The `/d1` subpath still exports `d1Storage` and `d1ActivityStore`. | Stop writers and restore a consistent backup with 0.37.1, then copy and verify before cutover. |
59
+ | `importStateFile`, `StateFileImport`, and `connecta migrate-state` | Named imports fail; the CLI command exits nonzero with usage. The SQLite adapter never reads the JSON file, so a fresh database has no old credentials or tokens. | Import on 0.37.1 while stopped, then point the deployment at that SQLite file. |
60
+ | Retired `execute.resumableWrites`, `execute.pausedRunTtlSeconds`, `identity`, `grant`, and deployment/pool `trust` migration hints | Construction still rejects these as ordinary unknown configuration options. It no longer expands identity keys or prints replacement instructions. Pool `grant` is also rejected. | Remove obsolete options. Follow [migration to 0.33](./migration-0.33.md) for `maintainers`, pool `members`, `agents`, and explicit `readOnly`. |
61
+
62
+ A rollback after accepting new SQL writes can resurrect revoked credentials or
63
+ spent refresh tokens. Recover from a consistent backup under maintenance rather
64
+ than merging old KV/JSON state into a live database. If preserving old auth is
65
+ unnecessary, reconnect credentials and issue fresh agent tokens in the current
66
+ SQL deployment; revoke superseded credentials at their providers.
67
+
68
+ ## Verify
69
+
70
+ Run `connecta doctor --pool <pool>` with each agent's token. Open each shared
71
+ and personal OAuth connection and make a controlled read. Confirm authorization
72
+ works without an unsupported-layout warning, the intended SQL database is used,
73
+ and the operator UI shows expected credentials and activity. Remove one-shot
74
+ migration routes and bindings after successful cutover.
@@ -24,24 +24,17 @@ committed through the deployment's own store, so the contract's `agents` and
24
24
  last seen are fixed. The restricted state is the member fixture from
25
25
  `test/fixtures/operator-contract-v2.ts`, and the endpoint and matrix variants
26
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
27
+ with `test/fixtures/operator-console.ts` crowding the people-only team pool so its avatar
28
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.
29
+ Collections use their corresponding browser types. Real contract serialization,
30
+ member projection and secret withholding are exercised through
31
+ `test/operator-contract.test.ts` and `test/operator-contract-server.test.ts`.
35
32
 
36
33
  `test/browser/operator-visual.spec.ts` intercepts API reads and serves the real
37
- hashed assets and HTML with the production CSP. Loading responses wait on an
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
42
- clock, UTC, en-US, locally hosted fonts, disabled animations, hidden carets,
43
- and a 1280 × 900 viewport. Narrow fixtures use 390 × 844. Every test waits for
44
- its state and fonts before capturing.
34
+ hashed assets and HTML with the production CSP. It captures populated Overview
35
+ and connector Connection pages in light and dark themes: four screenshots.
36
+ Each capture waits for the heading, page content and fonts, with a fixed clock,
37
+ and resets scrolling before the full-page image.
45
38
 
46
39
  ## Loading and recovery probes
47
40
 
@@ -52,115 +45,22 @@ The suite also checks default v2 compatibility, the unchanged member projection,
52
45
  blocked custom connectors and bounded essential token-slot failure.
53
46
  `test/ui.test.ts` checks complete detail schemas and independent sibling scope cleanup.
54
47
 
55
- `test/oauth-stored-observation.test.ts` covers absent, disconnected, tokenless,
56
- sealed/unreadable and issuer-mismatched grants, owner isolation, both built-in
57
- connector paths and custom connectors. Storage spies require zero auth mutations,
58
- including migration and resealing. `test/operator-store.test.ts` counts scoped
59
- refresh/focus/mutation/poll requests, coalescing and bounded retries, and verifies
60
- stale admission blocks privileged reads, connection writes and token actions while
48
+ `test/operator-store.test.ts` counts scoped refresh/focus/mutation/poll requests,
49
+ coalescing and bounded retries, and verifies stale admission blocks privileged reads, connection writes and token actions while
61
50
  retaining the snapshot. Late reads, role/identity changes and concurrent polls
62
51
  exercise publication fences. Browser recovery and flow suites use real routes to
63
52
  check a usable shell with a stalled connector, OAuth return and scoped Refresh.
64
53
 
65
- ## Page and state matrix
66
-
67
- Each row runs empty, loading, error, populated, and restricted-viewer fixtures
68
- in both light and dark themes, for 90 screenshots. The restricted viewer is a
69
- pool member, who gets the member page, with no tabs, on every path.
70
-
71
- | Page or tab | Empty state | Loading/error request | Restricted viewer (member) |
72
- | -------------------- | ------------------------------------ | --------------------- | ----------------------------------- |
73
- | Overview | No connectors: nothing to map | Config | Member page at `/` |
74
- | Endpoints | Root endpoint without tools | Config | Member page: endpoints, accounts |
75
- | Connectors | No connectors | Config | Member page, no connector request |
76
- | Connector Tools | Empty catalog | Config | Member page, no connector request |
77
- | Connector Connection | Deployment-managed auth | Config | Member page, no connector request |
78
- | Connector Activity | No calls | Activity | Member page, no activity request |
79
- | Tokens | No declared agents | Token list | Member page, no token request |
80
- | Activity | No calls | Activity | Member page, no activity request |
81
- | Settings | Snapshot without connectors or pools | Config | Member page, no configuration facts |
82
-
83
- Populated Overview has a failing connector, auth and credential problems
84
- and a tokenless agent in its attention list. Populated Endpoints shows who can use each endpoint; populated Tokens has one
85
- agent per slot state, with pools and last seen.
86
-
87
- Another 60 screenshots cover the Overview map on the frozen v2 maintainer, one
88
- person's trace, and the narrow map list; configured, mismatched, unreadable and multifield
89
- credentials; all three OAuth client mechanisms; clean and unobserved drift;
90
- historical Activity; client setup; schema dialog; read/write filters; narrow
91
- Settings; narrow sign-in and Connection; deployment branding; `/mcp`
92
- and an agent pool expanded with every runs-as kind; command search; narrow
93
- endpoints; the connector × endpoint matrix, one cell's open popover, and the
94
- narrow matrix; a new token's one-time secret dialog; and the member page, wide
95
- and narrow. `endpoints-expanded` and `narrow-endpoints` include the team row
96
- collapsed to "+3". The base
97
- populated Activity fixture includes grouped calls, an ungrouped legacy row,
98
- classification/result size/client facts, and a catalog-change event.
99
-
100
- `test/browser/operator-matrix.spec.ts` serves the frozen v2 fixtures to the
101
- real shell. It covers the matrix's table semantics, cell names, status dots,
102
- runs-as labels in each kind's popover, popover keyboard behavior, placement at a short viewport, the in-flow
103
- fallback without CSS anchors, and the absence of `style` attributes, agent URLs on Endpoints, the member page (its
104
- received body checked with `expectMemberViewWithholds`, `/ui/data` answering 404
105
- and never requested, no maintainer fact rendered, no maintainer request sent),
106
- the 401 sign-in and 404 no-access gates on `/ui/api/config` with no maintainer
107
- navigation, the shared recovery banner on Tokens and Activity through a failed
108
- refresh that stalls past its deadline (one focusable Retry, no maintainer
109
- request until Retry succeeds), an open client setup drawer closed by a failed
110
- refresh with focus on Retry, Tokens under recovery (an open rotate question
111
- closes with focus on Retry and nothing sent; an unseen secret dialog stays open
112
- over the banner until dismissed), payload sentinels, CSP, and the refusal of a v1 body. Matrix coverage excludes retired grants from
113
- its live counts and pie, keeps their names inspectable in the popover, and
114
- renders an unavailable catalog as a dashed empty ring with "?" and an unknown
115
- accessible name. Cell names distinguish equal grants against different live
116
- catalog sizes. `test/operator-endpoints.test.ts` covers those view-model cases,
117
- including a known empty catalog versus an unavailable one.
118
- `test/operator-connection-map.test.ts` also checks that a failed or unobserved
119
- catalog counts no tools, which the map draws as a muted dash, while a known
120
- empty catalog counts zero.
121
- `test/browser/operator-overview.spec.ts` covers the Overview on the frozen v2
122
- fixtures: the status pill, stat labels and numbers, map columns, dashed read-only grants and dotted
123
- tokenless access; attention rows with their fix links, a copied fix prompt equal
124
- to the catalogue's text, config order through a staggered full refresh, prototype-named
125
- connector IDs during loading and failure, and stable single-card height when
126
- its catalog empties. A single long-id, long-title card at 320, 390, 1024 and
127
- 1440px covers all eight status labels, both auth scopes, with and without the
128
- Read-only badge, tools and an action. Text rows stay single-line, full text
129
- remains accessible, links stay focusable, and the detail header and Overview
130
- attention rows retain their height; the hover
131
- sentence replacing the legend, and dimming; keyboard focus in column order with each node's sentence
132
- as its accessible name, Enter opening an endpoint's row and a connector; the
133
- narrow list, whose caller chips link where their map nodes do; an empty deployment; and a member at `/` getting the member page
134
- with no maintainer read, plus CSP and no `style` attributes.
135
- `test/browser/operator-console.spec.ts` covers UI-3: who-can-use chips by
136
- label, raw id and agent mark and "+N" from the keyboard; Tokens rows,
137
- issue with the once-only secret dialog, in-row rotate and revoke questions,
138
- 503, 499 and 409 failures that send exactly one request, slots missing from
139
- the list or left unresolved shown with disabled controls until Refresh; and the
140
- member page (its received body checked with `expectMemberViewWithholds`, no
141
- tabs, Search or maintainer fact, OAuth Connect, Reconnect and Disconnect sent as
142
- `?mode=continue`, `?mode=restart` and `DELETE`, the credential `actions`
143
- shapes, a refresh that drops an action closing its confirmation, a failed or
144
- stalled refresh keeping member chrome with Retry, a consent that outlasts the
145
- OAuth poll window), plus keyboard, sentinels, CSP and no `style` attributes.
146
- `test/operator-console.test.ts` covers the chip, slot-row and member-page view
147
- models. `test/browser/operator-scheme.spec.ts` holds the main bundle and checks the
148
- first painted background: saved dark on a light system paints dark, a pinned
149
- light deployment paints light over saved dark, and throwing storage keeps the
150
- system scheme while the released bundle settles on the normal bearer gate, and a
151
- sign-in there raises no error. The real-route token test in `test/browser/operator-ui.spec.ts` serves
152
- the contract, `/ui/data` and the slot routes from one real v2 deployment and
153
- checks that each mutation sent a distinct 22-character `expect`.
154
- `test/operator-store.test.ts` serves `/ui/api/config` from its own mock, so
155
- each test's data and detail answers stay separate, and covers role changes: a
156
- maintainer demoted after a failed refresh keeps no maintainer state and sends
157
- no maintainer request, and a promoted member loads maintainer data fresh. It
158
- also drives UI-3's slot fence with a session-token read held open: reloads and
159
- contract refreshes that move or drop a slot before dispatch, late results that
160
- cannot overwrite newer evidence, unknown and unreadable outcomes that only a
161
- later list read settles, revisions sent as `expect` and compared with the
162
- contract, an identity change that leaves the next identity's fence alone, and
163
- member actions whose `manage` a refresh changes.
54
+ ## Browser behavior evidence
55
+
56
+ | Suite | Assertions |
57
+ | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
58
+ | `test/browser/operator-matrix.spec.ts` | Members see their own page on every path, get scoped setup links, and never request maintainer data. |
59
+ | `test/browser/operator-overview.spec.ts` | Overview health, counts and map edges; per-caller status and principal-refusal copy without secret fix prompts. |
60
+ | `test/browser/operator-console.spec.ts` | Token issue/rotate/revoke confirmations and once-only secret display; member credential fields and OAuth connect/reconnect/disconnect controls. |
61
+ | `test/browser/operator-pages.spec.ts` | Resolved read/write filters, inert schema text, Activity history/grouping, and legacy URL redirects. |
62
+ | `test/browser/operator-shell.spec.ts` | Clerk loader and child-script behavior under CSP, with inline and foreign scripts blocked. |
63
+ | `test/browser/operator-ui.spec.ts` | Identity changes cancel reads and close popups, OAuth polling stays scoped, token mutations use real routes and distinct revisions, and declared agents show scoped credentials and usage. |
164
64
 
165
65
  Screenshots cover presentation. Keep unit and server tests for INV-6 sentinels,
166
66
  secret disclosure, auth and grant boundaries, CSRF, identity fences, cancellation,
@@ -113,6 +113,12 @@ Pool endpoint rows show the effective surface (`meta` or `native`) and whether
113
113
  code is on. These are read-only facts from deployment configuration; change
114
114
  `surface` and `executeCode` in deployment code.
115
115
 
116
+ Plain `/mcp` is routed by sign-in: the `/mcp` row and matrix column show the
117
+ whole catalog maintainers receive, and a pool row shows what its people
118
+ receive at both `/mcp/<pool>` and, when they belong to no other pool, plain
119
+ `/mcp`. A note above the rows says so. People in several pools appear in
120
+ `config.peopleInSeveralPools`; plain `/mcp` refuses them.
121
+
116
122
  One row each for `/mcp` and every pool: the path, a read-only pill on a
117
123
  read-only endpoint, a copyable URL, who can use it, its connectors as colored
118
124
  monograms (four, then "+N"), its tool count over a read and write bar, and a
@@ -121,7 +127,9 @@ Setup button.
121
127
  - Who can use it is `root.maintainers` on `/mcp` and the pool's `members`
122
128
  elsewhere, as an avatar stack named on hover and to screen readers (label,
123
129
  raw id when the label is null, or agent name). Four show, then a "+N"
124
- button. A pool with agent members labels its two URLs People and Agents.
130
+ button. A pool lists only people or only agents. An agent pool's row
131
+ still shows two URLs labeled People and Agents; the People URL
132
+ (`/mcp/<pool>`) admits no one, because the pool has no people.
125
133
  - Expanding a row lists everyone by name, then each connector with what it
126
134
  runs as and its tools, write tools amber with a pencil. Runs-as comes from
127
135
  the endpoint's matrix cell: "Shared · saved <date>", "Shared · connected
@@ -194,8 +202,9 @@ tabs:
194
202
  annotation badges (Destructive, Open world), filtered by search and All,
195
203
  Read and Write. A tool opens its schema in a side drawer.
196
204
  - **Connection.** An Authentication card (mode, OAuth client mechanism, who
197
- manages it, OAuth actions, and the credential card with masked last four,
198
- field states, and Replace, Test and Remove); a Diagnostics card of tiles
205
+ manages it, the last verification, OAuth actions, and the credential card
206
+ with masked last four, field states, and Replace, Test and Remove); a
207
+ Diagnostics card of tiles
199
208
  (catalog age and last call) with a fix prompt beside each
200
209
  problem; and a Configuration card. Its badges name the kind (Remote MCP,
201
210
  HTTP API or Custom), provider, auth scope, endpoint host and usage guide.
@@ -340,10 +349,12 @@ connections**, has no tabs; its heading shows the signed-in email when the
340
349
  sign-in exposes one (Clerk's primary email), and its top bar shows branding and
341
350
  an **Account** button with Sign out or Change token. It lists:
342
351
 
343
- - **Your endpoints**: one card per admitted `/mcp/<pool>` URL with a copy button
344
- and **Client setup**. For example, Bob in pool `team` copies
345
- `https://connecta.example.com/mcp/team` into an MCP client and authenticates
346
- as Bob.
352
+ - **Your endpoints**: one card per address with a copy button and **Client
353
+ setup**. A member of exactly one pool sees one card for plain `/mcp`, named
354
+ after the pool it serves; a member of several pools sees one
355
+ `/mcp/<pool>` card per pool. For example, Bob, only in pool `team`, copies
356
+ `https://connecta.example.com/mcp` into an MCP client and authenticates as
357
+ Bob.
347
358
  - **Your accounts**: the personal connectors in their pools, each with a
348
359
  monogram, tool count, one status badge in an aligned column, and only the
349
360
  controls its `manage.actions` lists. A saved credential that no longer fits
@@ -415,7 +426,8 @@ without this capability contribute an unconfirmed count of zero. For example,
415
426
  The maintainer view carries:
416
427
 
417
428
  - `config`, the construction-time `describeConfig()` snapshot, including
418
- `maintainers` and each pool's `members`, and `configSources`, which labels
429
+ `maintainers`, each pool's `members`, `peopleInSeveralPools` (non-maintainer
430
+ people plain `/mcp` refuses because they are in several pools), and `configSources`, which labels
419
431
  each serialized leaf as `default` or `config` from option presence rather
420
432
  than equality with the default. Factory descriptions carry relative
421
433
  `optionSources` paths so resolved module and transport defaults retain their
@@ -488,7 +500,9 @@ The maintainer view carries:
488
500
  The member view is exactly that member's projection: `config`,
489
501
  `configSources` and `root` are `null`, `live.connectors`, `agents` and
490
502
  `matrix` are empty, and `live.activity` is `"forbidden"`. `pools` lists only
491
- their pools, each with `owner: null` and `members: []`. `connectors` lists
503
+ their pools, each with `owner: null` and `members: []`. With exactly one pool,
504
+ its `humanPath` is `/mcp`, the address that serves them that pool, and the
505
+ member's catalog reads carry that pool as plain `/mcp` would. `connectors` lists
492
506
  each connector in those pools with its title, the member's pools that serve
493
507
  it, its auth scope, the tools those pools grant with their classification,
494
508
  `connection` (their own partition's state and problem code for a personal
@@ -556,6 +570,58 @@ the config snapshot, and never treats a `per_caller` overlay as an error.
556
570
  complete classified tools with input/output schemas, registration path, catalog
557
571
  age, and activity-derived last-call facts under the reader's disclosure policy.
558
572
  A failed or timed-out connector releases its own scope; siblings finish independently.
573
+ The status and catalog observation has its own deadline: 8 seconds, or
574
+ `discovery.probeTimeoutMs` when that is shorter, in which case the whole row
575
+ uses that one deadline. The 8-second value is fixed, not configured; agent
576
+ discovery keeps the full `discovery.probeTimeoutMs`. When the deadline ends
577
+ first, the downstream read is aborted and the row returns `status: "error"`
578
+ with `problem: "connector_timeout"` in the row and its overlay. The row still
579
+ carries its credential card and auth permissions, so a slow connector's slot
580
+ stays manageable. Any other failure keeps `connector_unavailable`. The
581
+ connector renders as **Not responding**, with fixed copy, a fix prompt and
582
+ Refresh.
583
+ **Stored status.** Each live `GET /ui/connectors/:id` records one status
584
+ observation for that connector and viewer partition before it answers: its
585
+ state, problem code, tool count and observation time. Authored static catalogs
586
+ such as `api()` connectors are recorded too, since their status still checks
587
+ auth. The record lives in the `connector-health:v1:` family under the same
588
+ owner partition as the catalog cache (principal, subject, caller identity and
589
+ pool, endpoint, described configuration and package version), so a personal
590
+ connector's observation is one person's. It also carries the catalog
591
+ generation read before the probe, through the request's read memo that the
592
+ catalog listing reuses. It holds no tools, schemas, status prose or
593
+ credential facts. It expires 120 seconds after it was observed, and lapses at
594
+ once when a credential change, OAuth connect or disconnect, or invalidation
595
+ rotates the generation. A read that ends at the row's own deadline, including
596
+ a configured `discovery.probeTimeoutMs` shorter than 8 seconds, records
597
+ `connector_timeout` before it answers. An observation is written only while
598
+ the caller is still waiting: a request its caller has already left starts no
599
+ write. A write that has started is never raced against a deadline or
600
+ detached, because a storage write cannot be withdrawn once sent. The request,
601
+ whether it times out or its caller leaves meanwhile, settles only after that
602
+ write does, bounded by the storage layer like every other awaited write, so
603
+ nothing commits after the request ends.
604
+
605
+ `GET /ui/connectors/:id?observation=stored` answers from a current observation
606
+ without probing the downstream. The row and overlay carry `observedAgeMs`, the
607
+ stored `status`, `problem` and `toolCount`, and `tools: []`; the tools stay in
608
+ the catalog cache. The credential card, drift, permissions and any
609
+ authorization link are computed fresh on every request. Without a current
610
+ observation the route does the live read and records it, with no
611
+ `observedAgeMs`. Nothing is refreshed after the response: no deferred work and
612
+ no `ctx.waitUntil`.
613
+
614
+ The browser asks each connector for its stored observation on the page load
615
+ that follows admission, and fixes the observation time once as each stored
616
+ row lands. The list card and the connector page mark a stored row the same
617
+ way, "Stored status, checked … ago", with an age that keeps counting, and
618
+ show its tools as awaiting the live read rather than as none. The browser then
619
+ sends one plain live read per stored row, through the same queue of eight
620
+ detail reads. A stored `connector_timeout` row is not read again on its own;
621
+ its mark says to Refresh, and it waits for Refresh like a live timeout.
622
+ Refresh, a single connector's read, recovery retries and OAuth polls always
623
+ read live.
624
+
559
625
  The summary and each detail carry `viewerKey` for the principal admitted to that
560
626
  request. The browser publishes the detail and overlay atomically only when that
561
627
  key matches admission. A changed viewer key, including an Access switch between
@@ -568,7 +634,7 @@ screen. The first answer for the new viewer triggers readmission, which clears
568
634
  everything retained.
569
635
  Config observations never
570
636
  overwrite a completed detail row. Each connector opens at most one live observation
571
- per page load; the summary `/ui/data` performs no downstream probes.
637
+ per page load, after its stored read; the summary `/ui/data` performs no downstream probes.
572
638
 
573
639
  `GET /ui/api/config?connector=<id>` narrows the same contract to one connector
574
640
  before status and catalog probes. For a maintainer, config, provenance, live
@@ -628,8 +694,23 @@ bounded at 2, 2, 4 and 8 seconds; a later focus return can try again after backo
628
694
 
629
695
  Connector Refresh, focus recovery and mutation follow-ups read only affected
630
696
  connectors. Focus probes unhealthy rows, never healthy siblings. All detail reads
631
- share a four-request limit and coalesce per connector. Failures retry only their
697
+ in one tab share an eight-request limit and coalesce per connector, so a page of
698
+ up to eight connectors loads in one round. The limit is fixed, not configured.
699
+ It bounds how many connectors one tab waits on at once; a tab still reads each
700
+ connector once per load, so the limit adds no requests to any one connector.
701
+ Detail reads do not consume `admission.requests` permits, which govern `/mcp`
702
+ only. They still share isolate CPU and memory, D1, and downstream account quotas
703
+ with agent traffic; each tab adds up to eight concurrent downstream reads, and
704
+ several connectors on one vendor account share that vendor's rate limit. Over HTTP/1.1 the browser itself allows about six
705
+ connections per origin.
706
+ Failures retry only their
632
707
  connector with the same bounded backoff; recovery never replays a mutation.
708
+ A `connector_timeout` row is parked instead. It spends its automatic retry
709
+ budget, and focus and visibility returns skip it. Only Refresh, a full refresh
710
+ or a mutation follow-up reads it again, so an outage holds a detail slot once
711
+ per explicit request, never repeatedly. An OAuth start's consent-return poll is
712
+ the exception: a timeout during its 30-second window keeps polling, and success
713
+ still stops it.
633
714
  Mutations cancel affected reads and advance their publication fence both at
634
715
  dispatch and on settlement, including failure. Follow-ups require an observation
635
716
  started after settlement, so a Refresh or retry started during the write cannot
@@ -638,9 +719,21 @@ while identity and full refresh revisions fence the complete view. An explicit
638
719
  OAuth start polls only that connector every two seconds for up to 30 seconds.
639
720
  Concurrent authorizations retain independent cancellation and publication. Success,
640
721
  failed reads, disconnect, navigation, unmount and identity reset stop the matching
641
- poll. Recovery never starts authorization. A scoped result cannot confirm identity,
722
+ poll; a `connector_timeout` result does not. Recovery never starts authorization. A scoped result cannot confirm identity,
642
723
  role, token slots or any other deployment-wide admission fact.
643
724
 
725
+ A credential connector's `/ui/data` and `/ui/connectors/<id>` row carries
726
+ `verification: { outcome, observedAt }` when a record of the stored save
727
+ exists (see [last verification](./auth.md#test-then-save-and-last-verification)).
728
+ The auth facts show it as **Last verified**: Verified, Saved without a test,
729
+ Rejected, Missing permission, Service unreachable, Test timed out or Test
730
+ failed, with its time. A maintainer's credential form on a testable connector
731
+ saves through **Test and save** (`verify: "test"`). A failed test leaves the
732
+ form open with fixed copy for its failure class, and adds **Save without
733
+ testing**, a save without `verify`. Test shows the same per-class copy and reloads
734
+ the connector so its last verification updates. The member page's
735
+ credential form saves without a test and offers Test once a value is stored.
736
+
644
737
  Unreadable credential metadata uses `configured: null`, including named fields,
645
738
  and renders as unavailable with a retry prompt. It does not claim that the slot
646
739
  is empty. Overview, Endpoints, Connectors, connector
@@ -699,10 +792,9 @@ the page's styles.
699
792
 
700
793
  `src/operator-ui/config-summary.ts` maps the snapshot and its provenance to
701
794
  those tiles: one table of limit labels, the formatters, and the walk that turns
702
- an unmapped key into an Other tile. `app/config-tiles.tsx` draws them, and
703
- `test/operator-config-summary.test.ts` checks formatting, provenance, unknown
704
- keys, an empty deployment, and that a real deployment's snapshot leaves no key
705
- unmapped.
795
+ an unmapped key into an Other tile. `app/config-tiles.tsx` draws them.
796
+ `test/browser/operator-flows.spec.ts` checks Settings provenance through the
797
+ production UI and real routes.
706
798
 
707
799
  The contract type is [contract.ts](https://github.com/zackbart/connecta/blob/main/src/operator-ui/contract.ts).
708
800
  [UI routes](https://github.com/zackbart/connecta/blob/main/src/routes/ui.ts) and
@@ -0,0 +1,44 @@
1
+ # Split mixed pools
2
+
3
+ Every pool must list only people or only `agent:` references. A mixed pool
4
+ throws `ConfigError` at construction naming the pool, for example
5
+ `ConnectaConfig.pools.team.members mixes people and agents; list only one kind.`
6
+ This also applies to personal pools with or without `owner`. Pool names and
7
+ connector ids do not decide membership type. People-only pools may retain an
8
+ `owner`; it never changes the account a person uses.
9
+
10
+ Before upgrading, inspect every pool's `members`, including generated lists.
11
+ For each mixed team pool, define its tool list once and create two pools:
12
+
13
+ ```ts
14
+ const teamTools = ["crm", "tickets"];
15
+ const pools = {
16
+ team: { tools: teamTools, members: ["user_alice", "user_bob"] },
17
+ "assistant-team": { tools: teamTools, members: ["agent:assistant"] },
18
+ };
19
+ ```
20
+
21
+ Keep the original human pool name when possible so people's existing
22
+ `/mcp/team` address stays valid. Point the agent harness at
23
+ `/agent/assistant-team` and update its tier list to that name. Copy the
24
+ original `readOnly`, `surface`, `executeCode` and `description` settings
25
+ to both new pools as appropriate so each preserves its intended behavior.
26
+ If the mixed pool set `owner`, keep `owner` on the agent pool: it is the
27
+ Workspace address the agent acts as, and without it Workspace connectors with
28
+ a mapping `subject` disappear for the agent. People never use `owner`; they
29
+ always act as themselves, so the people pool does not need it. Agent pools
30
+ never count toward a person's plain `/mcp` routing, so a person who was in
31
+ one mixed pool and no other still reaches the people pool at plain `/mcp`.
32
+
33
+ For personal `assistant-alice` pools, keep only `"agent:assistant"` in
34
+ `members` and retain the owner's Workspace address and tools. Give people
35
+ their own people-only pools. Workspace mapping connectors act as each person;
36
+ shared-auth connectors act as their saved account for every member, so review
37
+ those grants before copying personal tool lists.
38
+
39
+ An agent can still belong to many pools with one token. Tokens, credentials,
40
+ `poolFor` tier selection logic and the Eve helper need no changes beyond pool
41
+ names in client configuration. Rebuild and restart the deployment, then verify
42
+ people and agents can each open their intended endpoints. See
43
+ [Organizing an agent's pools](./auth.md#organizing-an-agents-pools) for the
44
+ complete layout.
@@ -1,15 +1,9 @@
1
1
  # Provider auth migration
2
2
 
3
- Hosted selections described in this historical migration are now removed.
4
- For Stripe, Vercel, Cloudflare, Notion, Mixpanel, and GitHub hosted connections,
5
- use the [current hosted MCP migration guide](./hosted-mcp-migration.md).
6
- The API migrations below remain applicable.
7
-
8
- Use this upgrade guide when moving a Stripe, Vercel, or Cloudflare
9
- deployment from 0.30 to 0.31, where `auth` selects each provider's
10
- implementation.
11
- [Deployment upgrades](./deploying.md#upgrade-an-existing-deployment) cover other
12
- version changes; [integrating services](./integrating.md) covers new connectors.
3
+ This guide covers the 0.30-to-0.31 change to auth-selected implementations.
4
+ For current versions, follow [deployment upgrades](./deploying.md#upgrade-an-existing-deployment)
5
+ and [hosted MCP migration](./hosted-mcp-migration.md); hosted selectors below
6
+ are historical.
13
7
 
14
8
  A dual provider requires `auth`. `{ type: "oauth" }` connects the vendor's
15
9
  hosted MCP server, OAuth only. A key type connects Connecta's REST connector
@@ -1,20 +1,9 @@
1
1
  # Notion, Vercel and Cloudflare migration for 0.29
2
2
 
3
- Hosted selections described in this historical migration are now removed.
4
- For Stripe, Vercel, Cloudflare, Notion, Mixpanel, and GitHub hosted connections,
5
- use the [current hosted MCP migration guide](./hosted-mcp-migration.md).
6
- The API migrations below remain applicable.
7
-
8
- Use this upgrade guide for an existing deployment.
9
- [Deployment upgrades](./deploying.md#upgrade-an-existing-deployment) cover other
10
- version changes; [integrating services](./integrating.md) covers new connectors.
11
- [The agent index](./README.md) routes package maintenance separately.
12
-
13
- This was the Phase 1 item 5d migration input for [Phase 5 release #709](https://github.com/zackbart/connecta/issues/709),
14
- which shipped as 0.29.0.
15
- Deployments that use Notion or Cloudflare must check their actual grants and
16
- connector ids in deployment configuration before that release.
17
- The provider audit establishes available auth modes, not production OAuth grants.
3
+ This guide records the 0.29 Notion, Vercel and Cloudflare option changes.
4
+ For upgrades to current versions, use [deployment upgrades](./deploying.md#upgrade-an-existing-deployment)
5
+ and [hosted MCP migration](./hosted-mcp-migration.md); the hosted selectors below
6
+ are historical and cannot be used in current configuration.
18
7
 
19
8
  Cloudflare's part of this guide is superseded: `cloudflare()` now selects its
20
9
  implementation by `auth` and its key connector is complete on its own. Follow