@zackbart/connecta 0.36.0 → 0.36.1

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 (58) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/README.md +1 -1
  3. package/bin/version.mjs +1 -1
  4. package/dist/http/hatch-paging.js +2 -2
  5. package/dist/http/paging.js +3 -88
  6. package/dist/http/provider.js +1 -2
  7. package/dist/http/tools.js +1 -23
  8. package/dist/program-writes.js +0 -1
  9. package/dist/providers/_shared/sensitive-fields.js +0 -16
  10. package/dist/providers/breeze/api.js +2 -2
  11. package/dist/providers/ccb/api.js +1 -1
  12. package/dist/providers/cloudflare/api.js +8 -8
  13. package/dist/providers/cloudflare/lib/config.d.ts +2 -1
  14. package/dist/providers/docs/api.js +1 -1
  15. package/dist/providers/drive/api.js +1 -1
  16. package/dist/providers/drive/lib/hatch.js +1 -1
  17. package/dist/providers/drive/tools.js +1 -1
  18. package/dist/providers/forms/api.js +1 -1
  19. package/dist/providers/forms/lib/hatch.js +1 -1
  20. package/dist/providers/forms/tools.js +1 -1
  21. package/dist/providers/github/api.js +1 -1
  22. package/dist/providers/github/lib/discovery.js +2 -2
  23. package/dist/providers/gmail/api.js +1 -1
  24. package/dist/providers/granola/api.js +155 -0
  25. package/dist/providers/granola/index.d.ts +10 -0
  26. package/dist/providers/granola/index.js +68 -0
  27. package/dist/providers/granola/openapi.generated.js +30 -0
  28. package/dist/providers/granola/safety.js +37 -0
  29. package/dist/providers/granola/skill.generated.js +5 -0
  30. package/dist/providers/granola/tools.js +2 -0
  31. package/dist/providers/overflow/api.js +26 -26
  32. package/dist/providers/planning-center/api.js +4 -4
  33. package/dist/providers/planning-center/lib/constants.d.ts +1 -1
  34. package/dist/providers/planning-center/lib/json-api.js +2 -2
  35. package/dist/providers/quickbooks/lib/query.js +1 -1
  36. package/dist/providers/quickbooks/safety.js +1 -1
  37. package/dist/providers/sheets/api.js +1 -1
  38. package/dist/providers/sheets/lib/hatch.js +2 -2
  39. package/dist/providers/sheets/lib/requests.js +1 -1
  40. package/dist/providers/slides/api.js +1 -1
  41. package/dist/providers/stripe/api.js +7 -7
  42. package/dist/providers/tithely/api.js +2 -2
  43. package/dist/providers/vercel/api.js +12 -12
  44. package/dist/providers/vercel/lib/pin.js +1 -1
  45. package/dist/routes/mcp.js +1 -1
  46. package/dist/runtime/admission.js +0 -12
  47. package/dist/storage/keys.js +2 -3
  48. package/dist/version.d.ts +1 -1
  49. package/dist/version.js +1 -1
  50. package/documentation/architecture.md +124 -74
  51. package/documentation/auth.md +9 -2
  52. package/documentation/code-mode.md +6 -6
  53. package/documentation/meta-tools.md +5 -2
  54. package/documentation/operator-tests.md +11 -2
  55. package/documentation/operator-ui.md +1 -2
  56. package/documentation/providers.md +110 -0
  57. package/package.json +6 -2
  58. package/templates/node/package.json +1 -1
@@ -17,7 +17,7 @@ import { pinAdmission, pinOptions, pinQuery, pinRoute, readPinnedTeam } from "./
17
17
  export const MAX_RESPONSE_BYTES = 8 * 1024 * 1024;
18
18
  export const READ_CAP_MS = 60_000;
19
19
  /** POSTs that only read, admitted by `vercel_api_read`. */
20
- export const READ_POSTS = [
20
+ const READ_POSTS = [
21
21
  ["POST", "/v2/observability/query", "Runs an Observability metrics query; Vercel persists nothing."],
22
22
  ["POST", "/v1/registrar/domains/availability", "Checks availability for a list of domains; buys nothing."],
23
23
  ["POST", "/v1/registrar/domains/price", "Quotes registrar prices for a list of domains; buys nothing."],
@@ -39,7 +39,7 @@ export function invalid(message) {
39
39
  export function compact(value) {
40
40
  return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== undefined));
41
41
  }
42
- export function truthy(value) {
42
+ function truthy(value) {
43
43
  return value === true || value === 1 || (typeof value === "string" && /^(?:1|true)$/i.test(value.trim()));
44
44
  }
45
45
  /**
@@ -155,34 +155,34 @@ class VercelIndex extends OperationIndex {
155
155
  }
156
156
  }
157
157
  export const vercelIndex = new VercelIndex(discoveryIndex(openapi), { vendor: "vercel", title: "Vercel" });
158
- export const vercelSafety = valueSafety(VERCEL_VALUE_SAFETY, () => vercelIndex);
158
+ const vercelSafety = valueSafety(VERCEL_VALUE_SAFETY, () => vercelIndex);
159
159
  const Query = Schema.Record(Schema.String, Schema.Union([Schema.String, Schema.Array(Schema.String)]));
160
160
  const params = (...names) => Schema.Struct(Object.fromEntries(names.map((name) => [name, Schema.String])));
161
- export const currentUser = get("currentUser", "/v2/user", { success: Schema.Unknown });
162
- export const teams = get("teams", "/v2/teams", { query: Query, success: Schema.Unknown });
163
- export const projectEnv = get("projectEnv", "/v10/projects/:idOrName/env", {
161
+ const currentUser = get("currentUser", "/v2/user", { success: Schema.Unknown });
162
+ const teams = get("teams", "/v2/teams", { query: Query, success: Schema.Unknown });
163
+ const projectEnv = get("projectEnv", "/v10/projects/:idOrName/env", {
164
164
  params: params("idOrName"),
165
165
  query: Query,
166
166
  success: Schema.Unknown,
167
167
  });
168
- export const upsertEnv = post("upsertEnv", "/v10/projects/:idOrName/env", {
168
+ const upsertEnv = post("upsertEnv", "/v10/projects/:idOrName/env", {
169
169
  params: params("idOrName"),
170
170
  query: Query,
171
171
  payload: Schema.Unknown,
172
172
  success: Schema.Unknown,
173
173
  });
174
- export const updateEnv = patch("updateEnv", "/v9/projects/:idOrName/env/:id", {
174
+ const updateEnv = patch("updateEnv", "/v9/projects/:idOrName/env/:id", {
175
175
  params: params("idOrName", "id"),
176
176
  query: Query,
177
177
  payload: Schema.Unknown,
178
178
  success: Schema.Unknown,
179
179
  });
180
- export const buildLogs = get("buildLogs", "/v3/deployments/:idOrUrl/events", {
180
+ const buildLogs = get("buildLogs", "/v3/deployments/:idOrUrl/events", {
181
181
  params: params("idOrUrl"),
182
182
  query: Query,
183
183
  success: Schema.Unknown,
184
184
  });
185
- export const runtimeLogs = get("runtimeLogs", "/v1/projects/:projectId/deployments/:deploymentId/runtime-logs", {
185
+ const runtimeLogs = get("runtimeLogs", "/v1/projects/:projectId/deployments/:deploymentId/runtime-logs", {
186
186
  params: params("projectId", "deploymentId"),
187
187
  query: Query,
188
188
  success: Schema.Unknown,
@@ -294,7 +294,7 @@ export const refuse = (call) => {
294
294
  }
295
295
  return undefined;
296
296
  };
297
- export function scope(call, teamId, pin) {
297
+ function scope(call, teamId, pin) {
298
298
  if (pin)
299
299
  return { ...call, query: pinQuery(vercelIndex, call, pin) };
300
300
  const query = { ...call.query };
@@ -374,7 +374,7 @@ export function queryOf(call) {
374
374
  export function queryPairs(call) {
375
375
  return Object.entries(queryOf(call)).flatMap(([key, value]) => (Array.isArray(value) ? value : [value]).map((value) => [key, value]));
376
376
  }
377
- export function sendVercel(connection, call, options, sendOptions) {
377
+ function sendVercel(connection, call, options, sendOptions) {
378
378
  return checked(() => {
379
379
  const server = checkServer(call.op.server);
380
380
  if (server)
@@ -34,7 +34,7 @@ const object = (value) => value !== null && typeof value === "object" && !Array.
34
34
  const fail = (reason) => {
35
35
  throw new ConnectorCallError("provider_permission_denied", `Vercel team pin: ${reason} Not sent to the requested resource.`, { retryable: false });
36
36
  };
37
- export function validatePin(options) {
37
+ function validatePin(options) {
38
38
  if (options.pin === undefined)
39
39
  return;
40
40
  const id = options.pin?.teamId;
@@ -268,7 +268,7 @@ function scopedToBody(handler, signal) {
268
268
  * The request's admission permit, owned by its Scope.
269
269
  *
270
270
  * Admission goes through the controller's Promise rather than its Effect
271
- * program (`acquireScoped`), on purpose. The pool is shared by every request
271
+ * program, on purpose. The pool is shared by every request
272
272
  * in the isolate, and a queued request is handed its permit from inside the
273
273
  * request whose body just ended. A fiber resumed there would authorize and
274
274
  * serve this request in that one's I/O context, which workerd refuses;
@@ -7,7 +7,6 @@
7
7
  // read its private bookkeeping, and one that emits nothing into the `.d.ts`.
8
8
  // Promise callers keep `acquire()`, which runs the same program through
9
9
  // runEdge; Effect callers come through this module and never see a Promise.
10
- import { Effect } from "effect";
11
10
  let program;
12
11
  /**
13
12
  * Install the controller's admission program. Called once, by
@@ -32,14 +31,3 @@ export function admit(controller, options = {}) {
32
31
  }
33
32
  return program(controller, options.signal, options.wait !== false);
34
33
  }
35
- /**
36
- * A lease owned by the enclosing Scope: released when the scope closes, on
37
- * success, failure, or interruption alike. The wait itself stays
38
- * interruptible — a queued request whose caller left must not hold its place
39
- * in line until the queue timeout.
40
- */
41
- export function acquireScoped(controller, options = {}) {
42
- return Effect.acquireRelease(admit(controller, options), (lease) => Effect.sync(() => lease.release()), {
43
- interruptible: true,
44
- });
45
- }
@@ -2,9 +2,8 @@
2
2
  //
3
3
  // A deployment has one KVStorage (D1 on Workers, SQLite on Node, memory in
4
4
  // tests), and every subsystem shares it. Sharing is safe because no two
5
- // families claim overlapping keys, and that is only checkable if every key is
6
- // built here: `test/storage-keys.node.test.ts` fails when another source file
7
- // spells one of these prefixes itself.
5
+ // families claim overlapping keys. Build every key here; persistence journeys
6
+ // check actual isolation through the deployment and its physical database.
8
7
  //
9
8
  // Each family records:
10
9
  //
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const CONNECTA_VERSION = "0.36.0";
1
+ export declare const CONNECTA_VERSION = "0.36.1";
package/dist/version.js CHANGED
@@ -1,3 +1,3 @@
1
1
  // Generated from package.json by scripts/generate-version.mjs.
2
2
  // Workers-safe: no runtime filesystem read or deployment override.
3
- export const CONNECTA_VERSION = "0.36.0";
3
+ export const CONNECTA_VERSION = "0.36.1";
@@ -763,9 +763,9 @@ adoption, OAuth handoff ownership, single-use connect links, every downstream
763
763
  OAuth grant write and consent claim, the result stash, and initialization of the cursor signing key.
764
764
 
765
765
  Every key is built in `src/storage/keys.ts`, which lists each family with its
766
- scope, version, codec, and TTL policy; `test/storage-keys.node.test.ts` fails when
767
- two families overlap, another source file spells a prefix (constant concatenation
768
- folded), or a storage call passes a key holding literal text. Core hands
766
+ scope, version, codec, and TTL policy. Deployed-consumer persistence journeys
767
+ check actual owner isolation in the physical database; key probes retain NUL
768
+ refusal. Core hands
769
769
  subsystems namespaced views: `conn:<id>:` per connector, `principal:<key>:` per
770
770
  personal registry, `results:` and `subject:<key>:` for result paging.
771
771
 
@@ -1266,20 +1266,16 @@ removed. Legacy hosted selectors fail at construction with the generic migration
1266
1266
  path. GitHub retains its scope-enforced App identity and exposes a bounded repository-read and release-write hatch plus local scope discovery, scoped data search and guarded merge.
1267
1267
 
1268
1268
  [Decision 0011](https://github.com/zackbart/connecta/blob/main/decisions/0011-provider-standard.md)
1269
- records the provider standard now implemented by all 15 maintained providers. It fixes
1269
+ records the provider standard implemented by every maintained provider. It fixes
1270
1270
  one folder layout per kind and fixed evidence names. `drift.json` gets a
1271
1271
  generated block and the guide a generated Conventions section, and every
1272
- `api()` surface gets one agent-facing shape. Providers completed two migration
1273
- steps: onto the kit with unchanged output, then onto the standard surface.
1274
- Both `PENDING.step1` and `PENDING.step2` in `test/provider-standard.ts` are empty;
1275
- every maintained provider now meets the standard without a migration exemption.
1276
- `test/provider-standard.node.test.ts` holds every maintained provider folder to the
1277
- standard, and `test/provider-conventions.test.ts` checks the surface rules on
1278
- Node. `providers:generate` writes the standard's derived parts and
1279
- refuses a provider past step 1 that breaks the `drift.json` rules, or one past
1280
- step 2 that breaks the guide rules: `drift.json` version 2's `generated` block
1281
- (operations from the kit's `ProviderKitFacts` and evidence digests), and a guide's `## Conventions`, rendered
1282
- from the definition's declarations into `skill.generated.ts`.
1272
+ `api()` surface gets one agent-facing shape. Every maintained provider meets the
1273
+ standard without a migration exemption. `test/provider-standard.node.test.ts`
1274
+ holds every provider folder to it, and `test/provider-conventions.test.ts`
1275
+ checks the surface rules on Node. `providers:generate` refuses drift (D) and
1276
+ guide (G) violations before writing. It derives `drift.json` version 2's
1277
+ `generated` block from kit operations and evidence digests, and the guide's
1278
+ `## Conventions` from definition declarations into `skill.generated.ts`.
1283
1279
  The generator requires `fixtures.ts` to export `createAuthored()` with a
1284
1280
  nonempty offline `staticTools` catalog. Its input/output schemas derive one
1285
1281
  paging convention, including `get_*`, hatch search and details, excluding
@@ -1291,8 +1287,9 @@ reports a nonzero explicit refusal count with singular/plural wording and
1291
1287
  points to the actual prefixed details tool with method/path lookup; it never
1292
1288
  embeds the refusal table. Unreviewed operations remain refused.
1293
1289
  `ProviderContext.usageGuide` selects a guide's `<!-- when: <key> -->` blocks
1294
- with the definition's `blocks`. `providers:check` reads both record versions,
1295
- reports a manifest operation no endpoint row records at the provider's level,
1290
+ with the definition's `blocks`. Maintained drift records use version 2;
1291
+ `providers:check` retains version-1 endpoint/manual record parsing for historical
1292
+ reports, while OpenAPI generation and checks use `evidence/openapi.json`. It reports a manifest operation no endpoint row records at the provider's level,
1296
1293
  and lists manual checks last verified more than 180 days ago. Its offline
1297
1294
  record validator, `scripts/drift-validate.mjs`, also gates `providers:generate`
1298
1295
  and the standard suite, so a record they accept is one `providers:check` reads.
@@ -1356,8 +1353,10 @@ acknowledgement, then reconciles vendor state with exactly one physical send.
1356
1353
  `test/provider-privacy-journey.node.test.ts` checks credential echoes over HTTP.
1357
1354
  Focused provider suites retain MIME/draft restrictions, revision conflicts,
1358
1355
  CCB routing, Planning Center product exclusions and deployment pins. Native
1359
- HTTP framing, cursor and request-lifetime fault probes remain in the HTTP suites;
1360
- catalog copies and decoder/adapter parity matrices are retired under #1072.
1356
+ HTTP framing, cursor and request-lifetime fault probes remain in the HTTP suites.
1357
+ The catalog-wide status sweep and its argument roster, catalog/ranking copies
1358
+ and unused paging strategy tests are retired under #1072. Provider workflows
1359
+ belong in the existing shared outcomes; a new tool requires no failure-matrix row.
1361
1360
  No legacy REST tool adapter remains.
1362
1361
  Large documents opt into generator options that drop restated operation ids
1363
1362
  and plain path parameters and cap one operation's details (`opBudget`).
@@ -1376,7 +1375,7 @@ schemaless and non-JSON responses declare no fields. Request shrinking and
1376
1375
  endpoint contract digests do not depend on this metadata.
1377
1376
  Fields remain optional additive metadata, so a previously compiled
1378
1377
  index without the source bytes remains usable without inventing a response
1379
- contract. Vercel's step-2 pin review restores response metadata from the reviewed public
1378
+ contract. Vercel's pin includes response metadata from the reviewed public
1380
1379
  document; operations without declared response properties still refuse fields. Breeze's pin declares no response
1381
1380
  properties. GitHub's immutable official OpenAPI pin supplies its complete index and response fields; a reviewed repository allowlist controls dispatch. Natural queries with reviewed matches scope discovery to those matches and named-only operations; explicit paths and unmatched queries retain full-pin refusal discovery.
1382
1381
  `check:providers-generated` checks each index header against its source record
@@ -1435,14 +1434,12 @@ every vendor ships one reviewed table through one mechanism
1435
1434
  signing, webhooks, drains, transfer, claim, and invite codes). It is the
1436
1435
  union of the detectors Cloudflare and Vercel shipped first, and
1437
1436
  deliberately over-inclusive. `providers:spec` writes
1438
- `evidence/value-safety.json` (`value-safety.candidates.json` until the
1439
- provider's step 1) when the source record sets
1437
+ `evidence/value-safety.json` when the source record sets
1440
1438
  `options.valueSafety` (vendor `operationWords`; Stripe's `expansions: false`
1441
1439
  skips id-or-object expansions, which are their own operations' candidates),
1442
1440
  stamped with the pinned digest, the detector format, and its options. The
1443
1441
  file is test evidence and never ships.
1444
- 2. **One reviewed verdict per candidate**, in the vendor's `safety.ts`
1445
- (`value-safety.ts` until its step 1):
1442
+ 2. **One reviewed verdict per candidate**, in the vendor's `safety.ts`:
1446
1443
  `refuse` (the generic tools refuse it before transport, naming the
1447
1444
  operation and the reason), `redact` (reviewed field paths), or `safe`, each
1448
1445
  with a reason. Paths are dot paths into the data a tool returns: a list on
@@ -1627,14 +1624,13 @@ response schema can return (through `options.valueSafety.dataRoot` for an
1627
1624
  envelope such as Cloudflare's `result`), and every resource rule path
1628
1625
  something the resource's schema can return. It stamps the paths that resolve
1629
1626
  into the candidates file and fails on the rest, unless the table's `absent`
1630
- field (`value-safety.absent.json` until the provider's step 1) acknowledges
1627
+ field acknowledges
1631
1628
  them with a reason (shared verdicts applied to operations whose schema lacks a
1632
1629
  path, or fields a schema leaves undeclared; such paths still apply at
1633
1630
  runtime).
1634
1631
 
1635
1632
  `test/fixtures/value-safety.ts` is the shared harness each vendor's
1636
- `value-safety.node.test.ts` (`provider.safety.node.test.ts` after its step 1)
1637
- runs; `reviewProblems` is pure, and
1633
+ `provider.safety.node.test.ts` runs; `reviewProblems` is pure, and
1638
1634
  `test/value-safety-harness.node.test.ts` proves wrong paths fail it. It fails
1639
1635
  on candidates from another pin, format, or option set; an unreviewed
1640
1636
  candidate; a verdict for an operation the index lacks; a table path the stamp
@@ -1672,21 +1668,74 @@ capture determinism. Production invariants remain unchanged.
1672
1668
  Use the existing stateful fixture vendors and published-edge deployment adapters:
1673
1669
 
1674
1670
  - `pnpm run eval:outcomes` drives representative joins, retained paging, endpoint
1675
- refusal, auth handoff, value safety and refund recovery. Graders inspect
1671
+ refusal, auth handoff, value safety and recovery after committed refunds,
1672
+ cancellations, DNS and environment updates, plus a single GitHub draft release
1673
+ and Google document partial creation and shared-drive permissions. Graders inspect
1676
1674
  independent downstream state and the physical mutation ledger, and reject
1677
1675
  wrong targets, duplicate writes, missing completion and interrupted trials.
1676
+ Every reference also rejects a fabricated correct answer without the work.
1677
+ Promoted read journeys reject erased MCP data even with the vendor ledger intact.
1678
1678
  - `pnpm run eval:smoke` boots the Node template, Node eval deployments and native
1679
- Workers deployments, including the actual QuickBooks provider, then exercises
1679
+ Workers deployments, including the actual QuickBooks and Granola providers, then exercises
1680
1680
  MCP and the operator page.
1681
+ - The shared `granola-workspace-journey` outcome uses actual provider reads,
1682
+ independent fake meeting state and physical cursor/filter requests on both
1683
+ Node/SQLite/QuickJS and native Workers/D1. It covers transcript-too-large
1684
+ recovery, empty intermediate pages, selected fields, withheld photo/credential
1685
+ values and shared-vault reuse after application reconstruction. No-op,
1686
+ fabricated-read and erased-delivery controls must fail.
1687
+ - `test/identity-write-journey.node.test.ts` uses the existing Node deployment
1688
+ adapter, stateful MCP fake, SQLite vault and QuickJS to grade admitted human
1689
+ and machine identities, pool isolation, fail-closed discovery, endpoint and
1690
+ connector policy, physical mutation counts, ambiguous-write reconciliation,
1691
+ credential ownership and payload-free activity. Independent decoding checks
1692
+ returned private values and credential echoes; positive record facts must
1693
+ still arrive. An explicitly writable pool also exercises reopening a
1694
+ read-only deployment without bypassing connector policy.
1695
+ - `test/cancellation-journey.node.test.ts` observes a queued client's departure
1696
+ without another vendor send, and an active client's departure after the
1697
+ vendor commits. The vendor must see its held response socket close before
1698
+ releasing it; a later MCP read recovers the committed intent exactly once.
1699
+ `test/cancellation-faults.test.ts` keeps signal-less token-resolution,
1700
+ warmed-credential digest, stalled body-cleanup and abort/grant races on Node
1701
+ and workerd. These replace the universal Promise-method/seam/owner matrix
1702
+ and its enrollment self-test, plus migration-only runtime wrapper checks.
1703
+ - `test/browser/operator-flows.spec.ts` serves the actual operator shell and
1704
+ routes over TCP with file-backed SQLite. Sign-in, Settings provenance, OAuth
1705
+ connect/disconnect and credential save/test/replace/remove survive closing and
1706
+ reopening the app, database and vault. An independent SQL connection reads
1707
+ trigger counts: one save, one replacement, one removal, and no credential
1708
+ writes from reads or a rejected replacement. A real SQL trigger failure leaves the old
1709
+ credential usable after restart. MCP calls verify that those edits preserve
1710
+ the reader pool's actual read access and write refusal. Activity renders
1711
+ successful calls recorded before restart without either credential value.
1712
+ - The existing Node-template `eval:smoke` target constructs invalid config from
1713
+ published imports before any I/O and reuses a stored token after restarting
1714
+ the consumer process. Its Worker-fakes target saves a personal credential in
1715
+ Chromium, refuses another owner's use, saves that owner's invalid credential,
1716
+ then restarts workerd on the same D1 directory. Actual downstream records
1717
+ remain readable only to the correct owner. Direct SQL inspection finds two
1718
+ distinct durable encrypted rows and exactly one committed save for each.
1719
+ - Keep focused SQL batch/schema/retention rollback, clock-skew and absolute
1720
+ expiry, NUL/UTF-8 and literal-prefix, cross-connection claims, cancellation,
1721
+ corrupt-row and tracing-secrecy probes. Keep operator identity/slot fences,
1722
+ deadlines, CSRF, restricted-view projection and sink secrecy probes. These
1723
+ cover faults that a successful browser journey cannot reproduce. Retired
1724
+ evidence includes the key-prefix source scanner, config expected-object
1725
+ matrices, operator structure snapshots and native-composition sentinels.
1681
1726
  - `test/provider-privacy-journey.node.test.ts` sends credentials through real
1682
1727
  HTTP MCP and a maintained API provider. Unknown vendor fields and keys carry
1683
1728
  raw, escaped, percent-encoded, base64 and Basic echoes through direct calls,
1684
1729
  QuickJS programs, failure and recovery. The independent decoder in
1685
1730
  `test/helpers/secret-echoes.ts` checks the wire responses for secret fragments;
1686
1731
  it does not normalize them to placeholders or compare saved output.
1687
- - `test/provider-failure-sweep.test.ts` checks retained catalog examples for
1688
- dispatched failure, classification, auxiliary and composite write outcomes.
1689
- New providers use the required deployment outcomes above. Existing
1732
+ - `test/provider-hostile-response.node.test.ts` reconciles real HTTP mutations
1733
+ after HTML, malformed JSON and oversized acknowledgements with one physical
1734
+ send. It distinguishes Stripe's reviewed pre-execution 401 refusal, and checks
1735
+ read failure facts, secrecy and recovery through direct and QuickJS calls.
1736
+ `test/provider-failure-sweep.test.ts` retains only concrete auxiliary, composite,
1737
+ in-flight and untracked-call fault probes; no provider/tool argument roster or
1738
+ catalog/finalizer agreement sweep remains. Existing
1690
1739
  `test/sent-secrets.test.ts`, `test/sent-secret-output-boundary.test.ts`,
1691
1740
  `test/request-secret-redaction.test.ts` and `test/catalog-secret-redaction.test.ts`
1692
1741
  cover secrecy before projection, truncation, caching, paging and diagnostics.
@@ -1695,11 +1744,24 @@ Use the existing stateful fixture vendors and published-edge deployment adapters
1695
1744
  Native transport parity, OAuth and write-provenance suites retain their
1696
1745
  workerd coverage. The shared throwaway RSA key in `test/fixtures/rsa.ts` is
1697
1746
  used by write-provenance and unknown-write-advice fixtures.
1698
- - The request, catalog, auxiliary-call, renewal and Promise-boundary lifetime
1747
+ - The request, catalog, auxiliary-call and renewal lifetime
1699
1748
  suites, plus `test/auth-admission-binding.test.ts`, exercise cancellation,
1700
1749
  held native work and garbage collection. These test actual request ownership;
1701
1750
  the retired capture scheduler's source guards were only harness constraints.
1702
1751
 
1752
+ The remaining probes defend distinct reachable failures: auth admission and
1753
+ native scheduler ownership, grant/callback fencing and refresh coordination,
1754
+ SDK replay/redirect/SSE attempts, nested write provenance and refusal evidence,
1755
+ unawaited program drain and failed-program accounting, catalog drift and paging
1756
+ revocation, and hostile serializers, structural echoes, truncation and persisted
1757
+ pages. Broad scripted-executor policy/privacy cross-products and repeated
1758
+ post-401 result/error-shape tables are retired. Protocol claims link executable
1759
+ evidence files in `spec/coverage.json`; the invariant contracts above are defended
1760
+ by the actual behavior assertions in these journeys and focused probes.
1761
+ The required CI gate includes build/declarations, Node and Workers probes,
1762
+ outcomes, browser flows, installed consumers and Docker, audits and real Eve
1763
+ compatibility. Further contributor cleanup is tracked in #1072.
1764
+
1703
1765
  Add a compact fault journey only for a meaningful outcome those suites cannot
1704
1766
  observe. Reuse their fixtures and adapters; do not reintroduce a snapshot
1705
1767
  format, module loader or virtual scheduler. Workerd enrollment is for native
@@ -1822,9 +1884,9 @@ declarations; elsewhere it lives in an unexported function or in
1822
1884
  (`ConnectorCallError`, `ExecutorAdmissionError`, `CallAdmissionError`) because
1823
1885
  callers and tests check `instanceof`, `name`, and `message`.
1824
1886
 
1825
- Effect callers skip the Promise and take the program: `admit` and
1826
- `acquireScoped` for request admission (`src/runtime/admission.ts`), `admitCall`
1827
- and `acquireCallScoped` for call admission, `closeScope` and `closeScopeOnExit`
1887
+ Effect callers skip the Promise and take the program: `admit` for executor
1888
+ admission (`src/runtime/admission.ts`), `admitCall` and `acquireCallScoped` for
1889
+ call admission, `closeScope` and `closeScopeOnExit`
1828
1890
  for a connector scope, `withDeadlineEffect` where Promise code has
1829
1891
  `withDeadline`. The build prunes every declaration no `exports` target reaches,
1830
1892
  and `pnpm run check:declarations` fails if what remains names an Effect type.
@@ -2044,8 +2106,8 @@ published storage interfaces.
2044
2106
  The synchronous state-file parser, validation, file read, and one atomic
2045
2107
  SQLite import remain native synchronous leaves because `importStateFile` is a
2046
2108
  published synchronous API. `openSqlite` retains file modes, WAL, busy timeout,
2047
- and database ownership. `test/sql-effect-contract.ts` runs native-path,
2048
- affected-row, 50-claim, cancellation, and tracing checks on SQLite and native
2109
+ and database ownership. `test/sql-effect-contract.ts` retains affected-row,
2110
+ 50-claim, typed-failure, cancellation, and tracing probes on SQLite and native
2049
2111
  D1. `test/kv-to-d1.test.ts` also reuses stores across separate workerd requests;
2050
2112
  the existing SQL contracts prove rollback, database-clock TTL, encodings,
2051
2113
  activity upgrades, and copy recovery.
@@ -2198,8 +2260,7 @@ ordinary Promise-based Connector factory. The kit stays outside the root
2198
2260
  graph and its Effect types are internal. In each provider, `api.ts` declares
2199
2261
  the vendor and `tools.ts` the tools.
2200
2262
 
2201
- Decision 0011's standard surface (Tithe.ly's step 2) adds four kit pieces.
2202
- A `list` without the legacy `key` returns `{ items, page }`, with
2263
+ The standard `list` builder returns `{ items, page }`, with
2203
2264
  `page.nextCursor` only while `hasMore`, and the kit appends `limit` (the
2204
2265
  declared default and maximum), `cursor` and `fields` to the tool's filters;
2205
2266
  `read` and `get` take `fields: true`. `src/http/fields.ts` narrows after every
@@ -2441,8 +2502,8 @@ after repairing/deleting a corrupt key, restart every process/isolate to clear
2441
2502
  cached keys. Pre-upgrade cursors require a new first page.
2442
2503
 
2443
2504
  The helper derives connection metadata and probe messages from
2444
- validated options and still accepts complete legacy usage guides for compatibility.
2445
- All maintained providers have completed the standard-surface migration.
2505
+ validated options and renders every maintained guide through
2506
+ `ProviderContext.usageGuide`.
2446
2507
  Candidate checks can refuse before authentication while
2447
2508
  preserving the provider's exact diagnostic. Its optional `authScope(options)`
2448
2509
  selector fixes OAuth grant ownership from deployment mode at construction;
@@ -2544,7 +2605,7 @@ dispatch.
2544
2605
 
2545
2606
  The generator's `allSuccessResponses: true` option unions JSON response fields
2546
2607
  from every 2xx. Existing providers keep the first JSON success contract until
2547
- their own reviewed regeneration; no committed provider index changes here.
2608
+ their own reviewed regeneration.
2548
2609
 
2549
2610
  `src/providers/_shared/google/hatch.ts` supplies JSON framing over the existing
2550
2611
  confined `Connection.sendPath`. It retains the hatch's origin/media guards,
@@ -2571,8 +2632,7 @@ For example, a direct value-mode result has outer `result.data`, the hatch's
2571
2632
  `result.data.page.nextCursor`, and vendor JSON at `result.data.data`:
2572
2633
  `call_tool({ address: "crm.forms_api_read", args: { path:
2573
2634
  "/forms/form_1/responses", cursor: previous.data.page.nextCursor },
2574
- resultMode: "value" })`. This is an envelope illustration for an opted-in
2575
- provider, not a claim that the Forms migration has shipped.
2635
+ resultMode: "value" })`. Google Forms uses this continuation envelope.
2576
2636
 
2577
2637
  `googleErrors(product, { standard: true })` declares the product's 404 meaning
2578
2638
  and uses common status fallbacks; revision-conflict meanings require a
@@ -2602,7 +2662,7 @@ Sheets declares its seven API methods in `src/providers/sheets/api.ts`; its
2602
2662
  kit tools retain the private digest-bound cell cursor, legacy A1 path encoding,
2603
2663
  and create/append recovery advice. Its projections and the Google failure
2604
2664
  classifier read fields by the names Google gave them, which the kit's parse pass
2605
- keeps. Its catalog and guide stay unchanged in step 1.
2665
+ keeps.
2606
2666
 
2607
2667
  Google's request adapter also offers a reviewed binary send. It marks the
2608
2668
  operation `googleBytes` for the product's `binaryBodies` selector and forwards
@@ -2814,8 +2874,8 @@ result handling, reviewed value safety and the deployment privacy projection
2814
2874
  before paging or provider projections can read it. Read methods beyond GET
2815
2875
  and HEAD require a review. Construction fixes each write step's capacity;
2816
2876
  the guarded transport reserves it before preparation and the shared core
2817
- decides the whole call's write outcome. Dedicated upload builders wait for
2818
- the Google Drive migration in C.7.
2877
+ decides the whole call's write outcome. Drive uploads use write builders over
2878
+ reviewed raw-body sends.
2819
2879
 
2820
2880
  Reviewed path calls resolve their actual method and path through an indexed
2821
2881
  safety adapter; a provider-supplied template cannot bypass the policy.
@@ -3026,7 +3086,8 @@ compiling and configuring the real thing.
3026
3086
  rejections are observed; dispatch and lease guards still contain detached
3027
3087
  work. Per-await I/O cancellation remains useful for releasing resources,
3028
3088
  while prompt refusal is enforced at the boundary
3029
- (`test/promise-boundary-lifetime.test.ts`). Invocation owns
3089
+ (`test/cancellation-faults.test.ts`, `test/operation-cancellation.test.ts`
3090
+ and `test/cancellation-journey.node.test.ts`). Invocation owns
3030
3091
  the recovery and logical-call records it reads after teardown. Closing an
3031
3092
  outer call also revokes nested calls paused in preparation. Request-owned
3032
3093
  MCP sessions and token flights outlive individual calls and close with the
@@ -3119,8 +3180,9 @@ compiling and configuring the real thing.
3119
3180
  at construction) and the predicate matched, which the ledger records on the
3120
3181
  request. Only Stripe declares it (`src/providers/stripe/api.ts`, reviewed
3121
3182
  as a `manual` check in its `drift.json`): an API v1 answer carrying Stripe's
3122
- `Request-Id`. `test/provider-failure-sweep.test.ts` holds that list to the
3123
- sources. Q8 is decided in one place, `settleWrite` in
3183
+ `Request-Id`. The real HTTP hostile-response journey checks this refusal
3184
+ against an ambiguous committed write; there is no copied declaration list.
3185
+ Q8 is decided in one place, `settleWrite` in
3124
3186
  `src/write-outcome.ts`, once per logical call and over every request it
3125
3187
  recorded. The invocation calls it for every failure of a served write: a
3126
3188
  thrown or mapped error, a custom connector's, a program's call, and its
@@ -3369,29 +3431,17 @@ compiling and configuring the real thing.
3369
3431
  `write_outcome_unknown`. The caller's own abort reason still passes by
3370
3432
  identity for a read and for a served call, whose timeout passes through
3371
3433
  unchanged for the invocation to report.
3372
- The catalog-driven `test/provider-failure-sweep.test.ts` checks every API
3373
- provider/tool on Node, fails on missing provider/tool examples or a
3374
- dispatched failure bypassing the helper, and covers served write/read
3375
- overrides with HTTP 503 for every tool and a connection reset after send
3376
- for each provider/verdict representative. HTTP 401 recovery uses those
3377
- representatives plus the distinct composite, auxiliary, owner-lookup and
3378
- POST-as-read paths.
3379
- Shared sender and real-socket evidence below own status/reset permutations.
3380
- Local metadata
3381
- tools prove zero sends; composite calls prove each distinct request leaves
3382
- once. The round-5 cases additionally cover Docs creation with initial text,
3383
- composite success followed by refusal, GitHub preflight failures, typed
3384
- handler errors after successful sends, Forms cursor conflicts after 200,
3385
- generic-code vendor refusals, auxiliary failures after resource dispatch,
3386
- redaction of refusal errors, and concurrent direct-call ledger isolation.
3387
- The round-6 cases cover a composite write's early refusal while siblings
3388
- await credentials or are in flight, requests started after the call ended,
3389
- connect-phase errnos with each body kind (all unknown for a write, and a
3390
- direct read stays retryable), a request aborted with a refusal-shaped
3391
- reason, an errno outside fetch's network error, and
3392
- undeclared handlers whose untracked send precedes a typed failure. Each
3393
- catalog case also checks that the ledger recorded every resource request
3394
- the network saw, and the inventory that every API connector declares it.
3434
+ Shared provider outcomes and the real HTTP hostile-response journey check
3435
+ returned data, failure/recovery, privacy and physical writes without a
3436
+ catalog-wide status matrix. `test/provider-failure-sweep.test.ts` retains
3437
+ fault probes for Docs creation with initial text, composite success followed
3438
+ by refusal, GitHub preflight failures, typed handler errors after successful
3439
+ sends, Forms cursor conflicts after 200, generic-code vendor refusals,
3440
+ auxiliary failures after resource dispatch and concurrent direct-call isolation.
3441
+ It also holds siblings awaiting credentials or already in flight when another
3442
+ write fails, refuses requests after call closure, and probes network errors,
3443
+ refusal-shaped abort reasons and untracked sends. Native transport and
3444
+ request-lifetime suites retain their platform-specific evidence.
3395
3445
  `test/write-evidence.test.ts` uses real refused, reset, and held sockets on
3396
3446
  both runtimes: a refused write is unknown and a refused read retryable,
3397
3447
  including a write aborted with another fetch's real refusal as its reason
@@ -412,6 +412,11 @@ agent. Enabling `preview` lets code on any pushed preview branch act as the agen
412
412
  Treat the project's OIDC token as a bearer credential for all of this agent's
413
413
  pools. Its default audience, `https://vercel.com/<team-slug>`, is shared by every
414
414
  service accepting Vercel's default OIDC tokens; it is not specific to Connecta.
415
+ Connecta accepts only that default audience. Vercel's custom-audience token
416
+ exchange can produce a validly signed token for another service; Connecta
417
+ refuses it. For example, a token exchanged for `https://tickets.example.com`
418
+ cannot authenticate to `/agent/assistant`. Resolve the ordinary workload token
419
+ with `getVercelOidcToken()` without an `audience` option.
415
420
  Anything holding the project's token can act as the agent:
416
421
  project code, builds (including build steps and dependency install scripts with
417
422
  access to `VERCEL_OIDC_TOKEN`), and services the project sends the token to,
@@ -2698,8 +2703,10 @@ The encoding lattice is exactly this, and anything outside it is out of scope:
2698
2703
 
2699
2704
  [Decision 0007](https://github.com/zackbart/connecta/blob/main/decisions/0007-agent-pool-layout.md)
2700
2705
  explains the pool layout; [decision 0006](https://github.com/zackbart/connecta/blob/main/decisions/0006-pools-are-the-access-model.md)
2701
- explains pools as the access model. `test/identity-scope.test.ts` checks identity
2702
- boundaries, and `src/storage/keys.ts` owns credential key families.
2706
+ explains pools as the access model. `test/identity-write-journey.node.test.ts`
2707
+ checks real HTTP identity, pool and personal credential isolation;
2708
+ `test/identity-scope.test.ts` retains handoff, callback and admission-revocation
2709
+ fault probes. `src/storage/keys.ts` owns credential key families.
2703
2710
 
2704
2711
  Inbound adapters live in [src/auth](https://github.com/zackbart/connecta/tree/main/src/auth);
2705
2712
  [auth routes](https://github.com/zackbart/connecta/blob/main/src/routes/oauth.ts)
@@ -1274,7 +1274,7 @@ rejection, and branded adapter acceptance across module copies.
1274
1274
  | `S9` | `test/result-shapes.test.ts` (value exclusion, bounds, merging, LRU and time expiry, runtime isolation, read-only admission, declared precedence, definition invalidation, unwrapped MCP results, discovery provenance, copy isolation, failure isolation) |
1275
1275
  | `S10` | `test/resource-read.test.ts` (qualified routing, whole-connector grants, personal credentials, redaction, admission, timeout, cancellation and downstream MCP reads), both guest-contract executors (successful resource reads and caught/uncaught typed failures) |
1276
1276
  | `E2`, `E8` | `test/guest-api-contract.test.ts` (code → `retryable`, caught, parallel, and uncaught validation recovery, a conflict's bounded `current`), `test/meta-tools-call.test.ts` (direct, destructive, provider fallback), `test/validate.test.ts` (bounded payload-free findings), `test/errors.test.ts` |
1277
- | `E3`, `E4` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (`auth_required`, destructive reroute), `test/program-writes.test.ts` (the refusal's `nextAction`, nothing sent, a caught refusal) |
1277
+ | `E3`, `E4` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (`auth_required`, destructive reroute), `test/identity-write-journey.node.test.ts` (read-only refusals before validation or dispatch, actual QuickJS) |
1278
1278
  | `E5` | `test/guest-api-contract.test.ts` (execution-failure channel, in-flight `cancelled`), `test/execute.test.ts` (admission), `test/executor-admission.test.ts`, `test/quickjs-executor.node.test.ts` (mid-run shutdown) |
1279
1279
  | `E6`, `X8` | `test/guest-api-contract.test.ts` (unknown and inherited members, retained error identities), `test/quickjs-executor.node.test.ts` |
1280
1280
  | `E7` | `test/guest-api-contract.test.ts` (refusals about a `503`-named connector), `test/errors.test.ts` |
@@ -1288,10 +1288,10 @@ rejection, and branded adapter acceptance across module copies.
1288
1288
  | `L3`, `X1` | `test/guest-api-contract.test.ts` (short-deadline executors), `test/execute.test.ts` (the watchdog ends a never-settling executor, frees the default pool, spares a slow run, and falls back from an unusable value) |
1289
1289
  | `L4`, `L8` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (shared discovery/call budgets and terminal catch-and-continue loops and queued-write cancellation on both executors), `test/worker-budget-response.node.test.ts` (native handle disposal and admission recovery across completed HTTP responses) |
1290
1290
  | `L5`, `L7`, `X2` | `test/quickjs-executor.node.test.ts` (CPU, heap), `test/execute.test.ts` and `test/executor-admission.test.ts` (bounded admission and queue) |
1291
- | `L6`, `X10` | `test/guest-api-contract-quickjs.node.test.ts` and `test/guest-api-contract.test.ts` (whole oversized reads and one-write pageable handles), `test/sqlite-storage.node.test.ts` and `test/d1-storage.node.test.ts` (shared stash transfers), `test/quickjs-executor.node.test.ts` (bridge and IPC bounds for arguments and result; the address in the over-bound message), `test/quickjs-child-stderr.node.test.ts` (outer reply serialization failure settles the call) |
1292
- | `V1`–`V4` | `test/guest-api-contract.test.ts` (dispatched calls, every refusal class including an address no connector owns, the friction each derives, no event for the execution itself), `test/activity.test.ts` (the shared code → friction table, the identity clamp, the one-attempt floor), `test/operator-view.test.ts`, `test/sql-storage-contract.ts`, run by `test/d1-storage.node.test.ts` and `test/sqlite-storage.node.test.ts` (historical pause and approval rows still render and round-trip) |
1293
- | `V5`, `W9` | `test/program-writes.test.ts` (an unawaited program write finished and recorded, its unknown outcome reported, counts on a failed program, the classification table), `test/invocation-pipeline.test.ts` (the gate after validation, an unrecorded refusal) |
1294
- | `W10`, `W12` | `test/program-writes.test.ts` (a writable endpoint's program write runs, a read-only endpoint omits writes from search and describe and refuses every write call on every path, including a write its guide names, a required deployment `readOnly`, the write budget, `readOnly` inheritance and overrides, `call_tool` still refusing, search and describe verdicts, construction refusals including retired `trust`), `test/operator-ui-model.test.ts`, `test/browser/operator-ui.spec.ts` (the badge) |
1291
+ | `L6`, `X10` | `test/guest-api-contract-quickjs.node.test.ts` and `test/guest-api-contract.test.ts` (whole oversized reads and one-write pageable handles), `test/sqlite-storage.node.test.ts` and `test/kv-to-d1.test.ts` (SQL stash and native D1 fault probes), `test/quickjs-executor.node.test.ts` (bridge and IPC bounds for arguments and result; the address in the over-bound message), `test/quickjs-child-stderr.node.test.ts` (outer reply serialization failure settles the call) |
1292
+ | `V1`–`V4` | `test/guest-api-contract.test.ts` (dispatched calls, every refusal class including an address no connector owns, the friction each derives, no event for the execution itself), `test/activity.test.ts` (the shared code → friction table, the identity clamp, the one-attempt floor), `test/browser/operator-ui.spec.ts` (identity changes), `test/sql-storage-contract.ts`, run by `test/sqlite-storage.node.test.ts` (historical activity rows still round-trip) |
1293
+ | `V5`, `W9` | `test/program-writes.test.ts` (unawaited program drain, failed-program accounting), `test/identity-write-journey.node.test.ts` (committed ambiguity, reconciliation and physical writes), `test/invocation-pipeline.test.ts` (the gate after validation, an unrecorded refusal) |
1294
+ | `W10`, `W12` | `test/identity-write-journey.node.test.ts` (real HTTP/MCP and QuickJS: write budget, read-only discovery and refusal, named guide, pool inheritance/reopening and connector policy), `test/program-writes.test.ts` (construction refusals and classification drift), `test/operator-ui-model.test.ts`, `test/browser/operator-ui.spec.ts` (the badge) |
1295
1295
  | `M1` | `test/guest-api-contract.test.ts` (invalid emits throw catchably, accept nothing), `test/execute-emit.test.ts` (rejected shapes, bounded native snapshots, paging before metadata traversal, and cyclic presentation refusal) |
1296
1296
  | `M2`, `M3` | `test/guest-api-contract.test.ts` (delivery order, truncated return plus delivered blocks), `test/execute-emit.test.ts` (envelope, `structuredContent`, byte-for-byte no-emit path) |
1297
1297
  | `M4` | `test/guest-api-contract.test.ts` (discard is visible), `test/execute-emit.test.ts` (structured and plain paths), `test/quickjs-executor.node.test.ts` (mid-run shutdown) |
@@ -1304,4 +1304,4 @@ rejection, and branded adapter acceptance across module copies.
1304
1304
 
1305
1305
  The surface itself is checked by `test/server.test.ts` (the exact six-tool list),
1306
1306
  `test/code-first-surface.test.ts` (construction, executor, removed tools, copy, and size),
1307
- and `test/program-writes.test.ts` (the retired pause options refused at construction).
1307
+ and `test/program-writes.test.ts` (deployment policy and classification construction refusals).
@@ -1334,8 +1334,11 @@ Connector ids already appear in native tool names. The
1334
1334
  operator UI and `describeConfig()` show every pool's effective `surface` and
1335
1335
  `executeCode` as facts from deployment code. Change these settings in code.
1336
1336
 
1337
- Keep native pools bounded. Comparisons so far used 40 synthetic tools;
1338
- large production catalogs near the cap have not been evaluated.
1337
+ Keep native pools bounded. Local real-Eve validation uses seeded catalogs from
1338
+ 40 through 1,000 downstream tools across meta, native and native-plus-code
1339
+ surfaces, with a deterministic model transport and no paid model calls. These
1340
+ checks establish local runtime contracts; model task quality and large
1341
+ production catalogs near the cap remain unmeasured.
1339
1342
 
1340
1343
  ### Eve agents
1341
1344