@zackbart/connecta 0.27.0 → 0.28.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 (42) hide show
  1. package/AGENTS.md +6 -6
  2. package/CHANGELOG.md +56 -0
  3. package/README.md +15 -19
  4. package/bin/connecta.mjs +1 -5
  5. package/dist/activity.d.ts +5 -4
  6. package/dist/activity.js +1 -10
  7. package/dist/artifacts/json.js +10 -0
  8. package/dist/artifacts/operations.js +1 -1
  9. package/dist/artifacts/validate.js +1 -2
  10. package/dist/catalog-service.js +1 -1
  11. package/dist/execute.js +92 -368
  12. package/dist/executors/quickjs.js +1 -1
  13. package/dist/exempt-writes.js +162 -0
  14. package/dist/index.d.ts +12 -31
  15. package/dist/index.js +14 -47
  16. package/dist/invocation.js +6 -19
  17. package/dist/meta-tools.js +1 -2
  18. package/dist/operator-ui/generated.js +1 -1
  19. package/dist/operator-ui/model.d.ts +3 -3
  20. package/dist/operator-ui/view.js +6 -4
  21. package/dist/routes/mcp.js +5 -21
  22. package/dist/routes/shared.d.ts +1 -6
  23. package/dist/server.js +0 -4
  24. package/dist/skills.js +8 -23
  25. package/dist/tool-safety.d.ts +1 -1
  26. package/dist/tool-safety.js +1 -1
  27. package/dist/types.d.ts +2 -2
  28. package/dist/version.d.ts +1 -1
  29. package/dist/version.js +1 -1
  30. package/documentation/architecture.md +10 -14
  31. package/documentation/code-mode.md +91 -194
  32. package/documentation/meta-tools.md +38 -41
  33. package/ethos.md +6 -7
  34. package/examples/worker/README.md +10 -14
  35. package/examples/worker/src/d1-activity-row.ts +4 -1
  36. package/examples/worker/src/index.ts +1 -9
  37. package/package.json +2 -2
  38. package/templates/node/AGENTS.md +4 -3
  39. package/templates/node/README.md +3 -4
  40. package/templates/node/package.json +1 -1
  41. package/dist/resumable.js +0 -1323
  42. package/dist/run-journal.js +0 -347
@@ -7,10 +7,10 @@ import type { CatalogAccessObservation, CatalogDriftReport } from "../types.js";
7
7
  *
8
8
  * - `runs_in_programs` — explicitly read-only, so `execute_code` may call it.
9
9
  * - `exempt` — not read-only, but the deployment's `execute.approval` lets a
10
- * program call it without pausing (#566). Still approval-required
10
+ * program call it without asking (#566). Still approval-required
11
11
  * everywhere else.
12
- * - `needs_approval` — everything else: a program pauses for
13
- * `resume_execution`, and a direct call crosses `call_destructive_tool`.
12
+ * - `needs_approval` — everything else: a program refuses it, and it crosses
13
+ * `call_destructive_tool`, where the host asks.
14
14
  *
15
15
  * The badge renders from a table keyed by this union, so each value is one
16
16
  * entry, not a branch.
@@ -413,12 +413,12 @@ export const TOOL_SAFETY_BADGE = {
413
413
  exempt: {
414
414
  label: "exempt from approval",
415
415
  tone: "neutral",
416
- title: "Not read-only, but this deployment's config lets programs call it without pausing. Each call still counts against the write budget and appears in activity; call_tool still refuses it.",
416
+ title: "Not read-only, but this deployment's config lets programs call it without asking. Each call still counts against the write budget and appears in activity; call_tool still refuses it.",
417
417
  },
418
418
  needs_approval: {
419
419
  label: "asks for approval",
420
420
  tone: "warn",
421
- title: "Not explicitly read-only: a program pauses for resume_execution, and a direct call crosses call_destructive_tool — either way the host asks first.",
421
+ title: "Not explicitly read-only: programs refuse it, and it runs through call_destructive_tool, where the host asks first.",
422
422
  },
423
423
  };
424
424
  /**
@@ -608,7 +608,8 @@ export function activitySummary(events) {
608
608
  return `${events.length} loaded call${events.length === 1 ? "" : "s"} · ${tools} tool${tools === 1 ? "" : "s"}`;
609
609
  }
610
610
  // A pause and an approval are neither success nor failure: each gets its own
611
- // class, and the stylesheet paints neither as an error.
611
+ // class, and the stylesheet paints neither as an error. Nothing has emitted
612
+ // either since issue #672 removed program pauses, but older rows carry them.
612
613
  const ACTIVITY_OUTCOMES = [
613
614
  "success",
614
615
  "error",
@@ -626,7 +627,7 @@ const OUTCOME_BADGE = {
626
627
  error: { label: "Failed", tone: "danger" },
627
628
  timeout: { label: "Timed out", tone: "danger" },
628
629
  cancelled: { label: "Cancelled", tone: "neutral" },
629
- paused: { label: "Waiting for approval", tone: "warn" },
630
+ paused: { label: "Paused for approval", tone: "warn" },
630
631
  approved: { label: "Approved", tone: "ok" },
631
632
  };
632
633
  export function activityOutcomeBadge(outcome) {
@@ -636,6 +637,7 @@ const SOURCE_LABELS = {
636
637
  execute_code: "In a program",
637
638
  call_tool: "Direct call",
638
639
  call_destructive_tool: "Direct call, approved by the host",
640
+ // History only: resume_execution left with program pauses (#672).
639
641
  resume_execution: "Resumed program",
640
642
  batch_call: "Batch call",
641
643
  };
@@ -4,9 +4,8 @@ import { notFoundResponse } from "../branding.js";
4
4
  import { registerExecuteTool } from "../execute.js";
5
5
  import { ExecutorAdmissionError, } from "../executor-admission.js";
6
6
  import { registerMetaTools } from "../meta-tools.js";
7
- import { registerResumeTool } from "../resumable.js";
8
7
  import { intersectAccess } from "../connector-access.js";
9
- import { instructionsFor } from "../skills.js";
8
+ import { CONNECTA_INSTRUCTIONS } from "../skills.js";
10
9
  import { msg } from "../errors.js";
11
10
  import { detach } from "../runtime/run.js";
12
11
  import { authorize, loggableValue, mayManageConnector, validateAuthPermissions, } from "./shared.js";
@@ -218,19 +217,14 @@ function toolkitRetired(logger) {
218
217
  },
219
218
  });
220
219
  }
221
- function serveMcp(request, requestSignal, opts, baseUrl, actor, registry, canManageAuth, poolName, runtimeContext) {
222
- // A paused run belongs to the endpoint it started on: resuming it through
223
- // another pool's endpoint finds nothing, as another subject would.
224
- const resumable = opts.resumable
225
- ? { ...opts.resumable, pool: poolName ?? null, approval: opts.approval }
226
- : undefined;
220
+ function serveMcp(request, requestSignal, opts, baseUrl, actor, registry, canManageAuth, runtimeContext) {
227
221
  // Every McpServer the request builds is fresh and closes with its scope.
228
222
  // The modern handler tears its own down after the exchange; the legacy
229
223
  // transport never does, and neither may stay wired to an ended request.
230
224
  const servers = [];
231
225
  const createServer = () => {
232
226
  const server = new McpServer(opts.serverInfo, {
233
- instructions: instructionsFor(resumable !== undefined),
227
+ instructions: CONNECTA_INSTRUCTIONS,
234
228
  cacheHints: {
235
229
  "tools/list": {
236
230
  ttlMs: 3_600_000,
@@ -274,7 +268,7 @@ function serveMcp(request, requestSignal, opts, baseUrl, actor, registry, canMan
274
268
  : {}),
275
269
  approval: opts.approval,
276
270
  });
277
- const runner = registerExecuteTool(server, registry, {
271
+ registerExecuteTool(server, registry, {
278
272
  baseUrl,
279
273
  executor: opts.executor,
280
274
  logger: opts.logger,
@@ -304,19 +298,9 @@ function serveMcp(request, requestSignal, opts, baseUrl, actor, registry, canMan
304
298
  ...(opts.watchdogMs !== undefined
305
299
  ? { watchdogMs: opts.watchdogMs }
306
300
  : {}),
307
- resumable,
308
301
  approval: opts.approval,
309
302
  maxWrites: opts.maxWrites,
310
303
  });
311
- // Always registered, so the surface is the same eight tools on every
312
- // deployment; without resumable writes it answers that there is nothing
313
- // to resume.
314
- registerResumeTool(server, registry, {
315
- runner,
316
- settings: resumable,
317
- ...(activity ? { activity } : {}),
318
- requestSignal,
319
- });
320
304
  servers.push(server);
321
305
  return server;
322
306
  };
@@ -527,7 +511,7 @@ export function createMcpRoute(opts) {
527
511
  if (new URL(request.url).searchParams.has("toolkit")) {
528
512
  return cors(toolkitRetired(opts.logger));
529
513
  }
530
- return cors(yield* serveMcp(localRequest, localAbort.signal, opts, baseUrl, authz.actor, scopedRegistry, id => { const connector = scopedRegistry.getConnector(id); return Boolean(connector && mayManageConnector(authz, connector)); }, poolName, runtimeContext));
514
+ return cors(yield* serveMcp(localRequest, localAbort.signal, opts, baseUrl, authz.actor, scopedRegistry, id => { const connector = scopedRegistry.getConnector(id); return Boolean(connector && mayManageConnector(authz, connector)); }, runtimeContext));
531
515
  });
532
516
  if (remainingMs === undefined)
533
517
  return yield* handled;
@@ -41,14 +41,9 @@ export interface ServerOptions {
41
41
  hostCallTimeoutMs?: number | undefined;
42
42
  /** Hard ceiling on one execute_code run, outside the sandbox. Default 120_000. */
43
43
  watchdogMs?: number | undefined;
44
- /** Resumable writes' settings; absent when they are off. */
45
- resumable?: {
46
- maxWrites: number;
47
- ttlSeconds: number;
48
- } | undefined;
49
44
  /** Config approval exemptions (`execute.approval`), resolved at construction. */
50
45
  approval?: ApprovalPolicy | undefined;
51
- /** Writes one program may send (`execute.maxWrites`), exempt ones included. */
46
+ /** Exempt writes one program may send (`execute.maxWrites`). */
52
47
  maxWrites?: number | undefined;
53
48
  /** Required sandbox backing the execute_code meta-tool. */
54
49
  executor: Executor;
package/dist/server.js CHANGED
@@ -52,10 +52,6 @@ export function createFetchHandler(opts) {
52
52
  ...(opts.executorName !== undefined
53
53
  ? { executor: { name: opts.executorName } }
54
54
  : {}),
55
- // Whether a program's write pauses for resume_execution or fails E4.
56
- // The tool is listed either way; this is the only place an operator
57
- // can see which answer it gives (#565).
58
- resumableWrites: opts.resumable !== undefined,
59
55
  // Counts only, from refreshes that already happened — the endpoint
60
56
  // asks no downstream anything, and `connecta doctor` reads it to
61
57
  // report a stale allowlist without a probe of its own (#343).
package/dist/skills.js CHANGED
@@ -1,24 +1,17 @@
1
1
  import { boundedEchoText } from "./errors.js";
2
- const ROUTE = "Choose a route before discovery. A known-address read needs only call_tool. Unknown-address read-only work starts with execute_code to discover, call, and return the answer; use the same route for reduction, multiple or dependent calls, loops, joins, or branches. Keep discovery and calls together when schemas suffice; do not return catalog matches alone. Inspect unfamiliar read results with a small sample before proceeding.";
2
+ const ROUTE = "Choose a route before discovery. A known-address read needs only call_tool. Unknown-address read-only work starts with execute_code to discover, call, and return the answer; use the same route for reduction, multiple or dependent calls, loops, joins, or branches. Keep discovery and calls together when schemas suffice; do not return catalog matches alone. Sample unfamiliar reads.";
3
3
  const RECOVERY = 'After auth_required use authorize_connector. After a truncated direct result use get_result. Guidance is on demand: fetch skills({ name: "usage" }) only when these instructions and the tool description are insufficient or a run needs repair.';
4
4
  /**
5
- * The MCP instructions of a deployment whose programs pause at writes. The
6
- * route sentence is its own, not ROUTE's: with writes in programs, "one known
7
- * write" is the only work left for call_destructive_tool, and an agent told
8
- * only that programs *may* write reads each write after a lookup as a known
9
- * one and sends them one prompt at a time.
5
+ * The always-loaded MCP `instructions` string. A program runs reads and the
6
+ * writes config exempts from approval; every other write is its own top-level
7
+ * call_destructive_tool, where the host's permission prompt is the approval.
10
8
  */
11
- export const CONNECTA_INSTRUCTIONS = `Choose a route before discovery. One known read: call_tool; one known write: call_destructive_tool. Everything else starts with execute_code to discover, call, and return the answer: unknown addresses, reduction, multiple or dependent calls, and writes that follow reads. Keep authorized batches in one program. Sample unfamiliar reads. Reduce a one-time write's full result there or page a direct call with get_result; never repeat it to recover output. Non-exempt program writes pause unsent; resume_execution with the returned token, address, and args approves the call and continues the program. Approval "tool" covers later same-address calls in this run; other approval-required writes need their own approval. ${RECOVERY}`;
12
- /**
13
- * The instructions of a deployment without resumable writes, whose programs
14
- * refuse every write: the routing it always had.
15
- */
16
- export const READ_ONLY_PROGRAM_INSTRUCTIONS = `${ROUTE} Only readOnlyHint: true tools run there. Keep catalog inspection and unannotated, write-capable, or destructive work top level: search_tools then call_destructive_tool when a call is needed. ${RECOVERY}`;
9
+ export const CONNECTA_INSTRUCTIONS = `${ROUTE} Only readOnlyHint: true tools and config-exempt writes run there. Keep catalog inspection and other unannotated, write-capable, or destructive work top level: search_tools then call_destructive_tool when a call is needed. Never repeat a write to recover its output. ${RECOVERY}`;
17
10
  const USAGE_SKILL_BASE = `# Connecta usage
18
11
 
19
12
  ## The surface
20
13
 
21
- Eight tools: \`execute_code\`, \`resume_execution\`, \`search_tools\`, \`call_tool\`, \`call_destructive_tool\`, \`authorize_connector\`, \`get_result\`, \`skills\`. Discovery and multi-call work live in a program. Top-level search remains for catalog inspection and approval-required work.
14
+ Seven tools: \`execute_code\`, \`search_tools\`, \`call_tool\`, \`call_destructive_tool\`, \`authorize_connector\`, \`get_result\`, \`skills\`. Discovery and multi-call work live in a program. Top-level search remains for catalog inspection and approval-required work.
22
15
 
23
16
  Follow the MCP instructions for routing. Read at most once for syntax or repair.
24
17
 
@@ -48,16 +41,14 @@ For top-level catalog inspection or approval-required discovery, omit \`limit\`
48
41
  - Preserve the schema's JSON types exactly: a numeric id is a number, not a numeric-looking string.
49
42
  - Validate tabular headers, row arrays, and row widths before mapping them. Never let a header or partial row become data.
50
43
 
51
- Only explicitly \`readOnlyHint: true\` or config-exempt calls run unasked. With resumable writes, non-exempt approval-required calls pause unsent; \`resume_execution\` repeats the pending address, args, and token. Without them, use \`call_destructive_tool\` for writes. Keep each authorized batch in one resumable program, final post included. \`approval: "call"\` covers one write; \`approval: "tool"\` covers later same-address calls in this run. Other approval-required writes need approval. Replay requires the same call order. Sandbox code cannot widen host gates.
44
+ Only explicitly \`readOnlyHint: true\` calls and writes the deployment's config exempts from approval run in a program. Any other write is refused before it is sent: send it through top-level \`call_destructive_tool\`, where the host asks. Sandbox code cannot widen host gates.
52
45
 
53
46
  ## Errors and repair
54
47
 
55
48
  Caught Connecta errors expose \`message\`, \`code\`, \`retryable\`, and \`details\`. Promise rejections retain these fields. Branch on fields, never prose. After a shared argument failure, repair one call before repeating it across other records. Do not retry \`retryable: false\`, and do not retry \`rate_limited\` immediately because portable code has no timer.
56
49
 
57
50
  - \`destructive_tool_requires_approval\`: stop and send the returned address through top-level \`call_destructive_tool\`.
58
- - \`execution_paused\`: the run already stopped at a write; let it end.
59
- - \`write_outcome_unknown\`: sent but unanswered, never re-sent; check the target.
60
- - \`execution_expired\`, \`_diverged\`, \`_interrupted\`: check \`writes\`, then rerun.
51
+ - \`write_outcome_unknown\`: an exempt write was sent but unanswered and is never re-sent; check the target.
61
52
  - \`auth_required\`: let the failure reach the model, then use top-level \`authorize_connector\`, give its handoff to the operator, and retry after recovery.
62
53
  - Truncated direct call: page with \`get_result\`, never repeat a write. A program result has no page handle; reduce a read in a new program. After a write, check the target or report the gap.
63
54
  - Unknown addresses and tools carry scoped search recovery. Use it inside the current run. Do not invent an address.
@@ -72,8 +63,6 @@ The \`execute_code\` description states this deployment's host-call and write bu
72
63
 
73
64
  Portable code uses standard JavaScript builtins, \`connecta\`, and \`console.*\`. QuickJS blocks imports and lacks fetch, process, timers, crypto, and WebSocket. Dynamic Workers must use only \`{ loader }\`; bindings, modules, or globalOutbound grant ambient authority. With loader only, environment maps are empty; node:fs/http/https are absent; outbound fetch, WebSocket, node:net, and node:tls are denied; DNS is unresolved. Runtime builtins remain through \`import()\` and \`process.getBuiltinModule()\`, including node:path and cloudflare:workers; this set can drift. Timers, process, crypto, WebSocket, and data: fetch remain. Avoid every runtime-only capability because QuickJS fails.
74
65
 
75
- \`Date.now()\` is the run's start and does not advance; \`Math.random()\` is seeded per run.
76
-
77
66
  ## Examples
78
67
 
79
68
  One read-only call at a known address:
@@ -113,10 +102,6 @@ Connector guides appear in \`skills({})\` and discovery with an exact \`guide\`
113
102
  `;
114
103
  /** Shared Connecta routing guidance, byte-identical across deployments. */
115
104
  export const USAGE_SKILL = USAGE_SKILL_BASE + CONNECTOR_GUIDES_SECTION;
116
- /** The always-loaded MCP `instructions` string. */
117
- export function instructionsFor(resumableWrites) {
118
- return resumableWrites ? CONNECTA_INSTRUCTIONS : READ_ONLY_PROGRAM_INSTRUCTIONS;
119
- }
120
105
  /** True when at least one of `connectors` carries a usage guide. */
121
106
  export function hasConnectorGuides(connectors) {
122
107
  return connectors.some((connector) => connectorGuide(connector) !== undefined);
@@ -20,7 +20,7 @@ export interface ApprovalPolicy {
20
20
  }
21
21
  export declare const NO_EXEMPTIONS: ApprovalPolicy;
22
22
  /**
23
- * Whether a program may call this tool without pausing for approval.
23
+ * Whether a program may call this tool without asking for approval.
24
24
  *
25
25
  * Only a tool that is *not* explicitly read-only can be exempt — a read-only
26
26
  * tool needs no exemption, and reporting one would blur the two classes an
@@ -14,7 +14,7 @@ export const NO_EXEMPTIONS = {
14
14
  tools: new Map(),
15
15
  };
16
16
  /**
17
- * Whether a program may call this tool without pausing for approval.
17
+ * Whether a program may call this tool without asking for approval.
18
18
  *
19
19
  * Only a tool that is *not* explicitly read-only can be exempt — a read-only
20
20
  * tool needs no exemption, and reporting one would blur the two classes an
package/dist/types.d.ts CHANGED
@@ -253,8 +253,8 @@ export interface Connector {
253
253
  /**
254
254
  * This connector's own default for its tools that are not explicitly
255
255
  * read-only, inside `execute_code`: `"never"` lets a program call them
256
- * without pausing for approval. Reserved for connectors connecta ships
257
- * whose writes are cheap to undo (the planned artifacts connector, whose
256
+ * without asking for approval. Reserved for connectors connecta ships
257
+ * whose writes are cheap to undo (the artifacts connector, whose
258
258
  * every write is a new immutable version); a deployment's own connectors
259
259
  * leave it unset and exempt through `execute.approval`, which overrides
260
260
  * this either way. Never read from a downstream catalog — a server cannot
package/dist/version.d.ts CHANGED
@@ -4,4 +4,4 @@
4
4
  * a bump that forgets this file fails the build rather than shipping a stale
5
5
  * version to `/health` and to downstream MCP handshakes.
6
6
  */
7
- export declare const CONNECTA_VERSION = "0.27.0";
7
+ export declare const CONNECTA_VERSION = "0.28.0";
package/dist/version.js CHANGED
@@ -4,4 +4,4 @@
4
4
  * a bump that forgets this file fails the build rather than shipping a stale
5
5
  * version to `/health` and to downstream MCP handshakes.
6
6
  */
7
- export const CONNECTA_VERSION = "0.27.0";
7
+ export const CONNECTA_VERSION = "0.28.0";
@@ -61,7 +61,7 @@ top to bottom.
61
61
  | 2 | MCP preflight | Allowed `OPTIONS` on `/mcp*`: 204 without admission or auth. |
62
62
  | 2 | Other `OPTIONS` | Auth metadata first, otherwise compatibility CORS preflight. |
63
63
  | 3 | `/.well-known/*` | Auth metadata, or 404. |
64
- | 4 | `/health` | Open and payload-free: health, executor, whether resumable writes are on, admission, and deployment metadata, with drift as stable short hashes. |
64
+ | 4 | `/health` | Open and payload-free: health, executor, admission, and deployment metadata, with drift as stable short hashes. |
65
65
  | 5 | `/oauth/callback/<connectorId>` | Core downstream OAuth completion, state and personal-ownership checked, independent of the UI. |
66
66
  | 6 | `/mcp`, `/mcp/<pool>` | Admission, then auth, then a request-local MCP server. An undeclared pool, a refusing grant, and a throwing grant are one identical 404; see [pools](./auth.md#pools). |
67
67
  | 7 | Other paths | 404. Custom HTTP routes belong to the deployment. |
@@ -94,7 +94,7 @@ An admitted non-preflight `/mcp` request then takes five steps in
94
94
  5. **Serve.** Refuse `?toolkit=` with a 404 — the toolkits are gone
95
95
  ([#178](https://github.com/zackbart/connecta/issues/178)) but their URLs were
96
96
  handed out, and retiring a scoping boundary into fail-open is worse than any
97
- 404 — then register the eight meta-tools on a fresh `McpServer`
97
+ 404 — then register the seven meta-tools on a fresh `McpServer`
98
98
  (`test/server.test.ts`, `test/code-first-surface.test.ts`).
99
99
 
100
100
  ## Layers below the meta-tools
@@ -109,7 +109,7 @@ or hands out, and a change usually belongs in exactly one of them:
109
109
  | `src/invocation.ts` | One tool call: argument validation, call admission, one-attempt timeout, provider retry hints, result unwrapping, size capping, and the activity record. |
110
110
  | `src/catalog.ts` | Ranking, description summarizing, and the compact and TypeScript schema renderers discovery shows. |
111
111
  | `src/result-shapes.ts` | Bounded runtime-only inference and merging for output shapes learned from successful read-only calls whose providers declared none. |
112
- | `src/resumable.ts`, `src/run-journal.ts` | Resumable writes: a program's host-call numbering, the write gate that pauses it, the journal a paused run becomes, the replay `resume_execution` plays from it, and the claim and write-ahead marks that keep an approved write to at most one send. |
112
+ | `src/exempt-writes.ts` | The writes a program may send, which config exempted from asking: the write budget's default, what a dispatched write's outcome says about whether it landed, and the tracking that lets one outlive the program without hiding an unknown outcome. Every other program write is refused before it reaches this. |
113
113
 
114
114
  `src/meta-tools.ts` and `src/execute.ts` are two front doors onto the same two
115
115
  services, `CatalogService` and `InvocationService`. That is the point: a
@@ -222,12 +222,10 @@ successful call's preview and a paging-unavailable notice rather than a result i
222
222
  A second optional method, `compareAndSet(key, expected, next, options?)`, is an
223
223
  atomic claim: `null` means absent (expired counts) on the way in and delete on
224
224
  the way out. A successful write accepts the same optional `ttlSeconds` as
225
- `set`. Resumable writes require it: of two `resume_execution` calls racing
226
- for one paused run exactly one may win, and every write that run sends is
227
- marked on its header first, so a read and a write standing in for the claim
228
- could send an approved write twice. Omitted, `execute.resumableWrites` is on
229
- exactly when the store has it, and asking for it over a store without it
230
- refuses to construct. Downstream OAuth uses it where the store has it, so
225
+ `set`. Artifacts require it, because every write commits by swapping a head,
226
+ and so does issuing access tokens; a read and a write standing in for the
227
+ claim would let two writers both win. Downstream OAuth uses it where the store
228
+ has it, so
231
229
  resealing legacy plaintext and discarding a refused grant cannot overwrite a
232
230
  consent that landed in between, and falls back to a read and a write where it
233
231
  does not.
@@ -330,7 +328,7 @@ owner admitted to `set_refresh` is stored with the program. Every run rechecks
330
328
  that identity's current `connectorAccess` and pool grant, including continued
331
329
  access to `artifacts.set_refresh`, then intersects those grants with shared
332
330
  connectors. Revoking either grant stops later runs.
333
- Resumable writes and approval exemptions are off. A refused call fails the
331
+ Approval exemptions are off, so a refresh writes nothing. A refused call fails the
334
332
  entire refresh even if its program catches the error. The head CAS claims one
335
333
  run per artifact; the data commit checks the claim ID and program version in
336
334
  the same CAS. The claim deadline starts before executor admission and aborts
@@ -483,7 +481,6 @@ would be another partition's.
483
481
  | Admission (`executor-admission.ts`, `call-admission.ts`) | Queued waiters are Deferreds settled by whoever removes them from the queue; a wait is one flat race of grant, Clock timeout, and signal. The uncontended path stays synchronous. Two controllers, as [#453](https://github.com/zackbart/connecta/issues/453) requires. |
484
482
  | One tool call (`invocation.ts`) | One fiber: resolution, the read-only and schema refusals, admission, and the downstream attempt sit under a single `withDeadlineEffect`, whose expiry interrupts the call wherever it is. The permit is an `acquireRelease`; the connector call is `Effect.tryPromise` over the unchanged `Connector`. |
485
483
  | `execute_code` (`execute.ts`) | One fiber whose Scope owns the run's signal and executor lease, so a result, a throw, the watchdog, and cancellation all release the lease and abort the signal the same way. The executor's `acquire()` and `execute()` stay Promises raced against the signal and `execute.watchdogMs`. Each guest host call is a fiber of its own. |
486
- | Resumable writes (`resumable.ts`) | A play's stop is a Deferred its write gate completes, raced against the executor like the watchdog; the gate for call n awaits the decision Deferreds of every lower-numbered call; header writes are one compare-and-set at a time on a per-play turn. A paused run holds nothing request-bound — its journal is data, and the next play is a new request's. |
487
484
  | Discovery (`catalog-service.ts`) | A request-scoped cache: one shared read per connector (`runtime/shared-read.ts`), settled by the read itself and carrying its own signal and the probe timeout whichever asker starts it. Each asker waits under its own deadline and signal, so one that times out or is cancelled fails alone, and the read is cancelled only once every asker has gone. Fan-out is `Effect.forEach` under the discovery concurrency. |
488
485
  | Registry (`registry.ts`) | Catalog persistence and the result stash are programs over `Storage`. A refresh flight is a Deferred its publishing request completes, bounded by its owner's deadline (the default probe timeout when it has none); persisted-catalog writes take per-connector turns, each a Deferred its own request completes. Same-request loads share one read the way discovery's do. |
489
486
  | Remote MCP (`connectors/remote-mcp.ts`) | Each request scope's state holds a Scope, each connection is a lease forked from it, and a connect in flight is a Deferred carrying the client it connected. Closing a session and the transport are each bounded to a second. |
@@ -589,9 +586,8 @@ cap. Effect can reject excess properties when both decoding and rendering use
589
586
  `onExcessProperty: "error"`; its default strips them. The generated schemas
590
587
  still differ from the exact meta-tool goldens, including record rendering and
591
588
  composed numeric bounds. A Schema replacement would need to preserve that
592
- contract, memoized rendering, and the raw-argument checks used by resumable
593
- writes. Both MCP SDK packages still depend on Zod, so changing our inputs alone
594
- does not remove Zod from an installation.
589
+ contract and memoized rendering. Both MCP SDK packages still depend on Zod,
590
+ so changing our inputs alone does not remove Zod from an installation.
595
591
 
596
592
  A one-endpoint `HttpApi` prototype adds 106,634 bytes gzip to `./ui` and 106,453
597
593
  to `./activity`. Even plain `HttpRouter` adds 45,324 to `./ui`, taking it to