@zackbart/connecta 0.35.0 → 0.36.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 (63) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/README.md +8 -4
  3. package/bin/version.mjs +1 -1
  4. package/dist/auth/downstream-oauth.js +71 -79
  5. package/dist/auth/static-oauth.js +104 -26
  6. package/dist/connectors/api-connector.d.ts +17 -0
  7. package/dist/connectors/api-connector.js +3 -1
  8. package/dist/http/client.js +1 -1
  9. package/dist/http/paging.js +1 -2
  10. package/dist/http/services.js +1 -1
  11. package/dist/http/tools.js +0 -4
  12. package/dist/operator-ui/contract.d.ts +1 -0
  13. package/dist/operator-ui/generated.js +4 -4
  14. package/dist/providers/_shared/google/kit.js +29 -139
  15. package/dist/providers/_shared/rest/kit.js +4 -404
  16. package/dist/providers/docs/tools.js +1 -2
  17. package/dist/providers/drive/api.js +1 -1
  18. package/dist/providers/forms/tools.js +1 -2
  19. package/dist/providers/gmail/tools.js +2 -2
  20. package/dist/providers/planning-center/lib/constants.d.ts +1 -1
  21. package/dist/providers/quickbooks/api.js +299 -0
  22. package/dist/providers/quickbooks/index.d.ts +13 -0
  23. package/dist/providers/quickbooks/index.js +93 -0
  24. package/dist/providers/quickbooks/lib/query.js +118 -0
  25. package/dist/providers/quickbooks/lib/writes.js +168 -0
  26. package/dist/providers/quickbooks/safety.js +222 -0
  27. package/dist/providers/quickbooks/skill.generated.js +5 -0
  28. package/dist/providers/quickbooks/tools.js +117 -0
  29. package/dist/providers/sheets/tools.js +1 -2
  30. package/dist/providers/slides/tools.js +2 -2
  31. package/dist/providers/vercel/index.js +1 -2
  32. package/dist/routes/oauth.js +3 -0
  33. package/dist/runtime/call.js +0 -4
  34. package/dist/skills.js +0 -1
  35. package/dist/types.d.ts +2 -0
  36. package/dist/ui.d.ts +1 -1
  37. package/dist/ui.js +0 -1
  38. package/dist/version.d.ts +1 -1
  39. package/dist/version.js +1 -1
  40. package/documentation/README.md +1 -0
  41. package/documentation/architecture.md +134 -301
  42. package/documentation/auth.md +47 -17
  43. package/documentation/integrating.md +1 -1
  44. package/documentation/meta-tools.md +1 -1
  45. package/documentation/operator-ui.md +16 -3
  46. package/documentation/providers.md +382 -0
  47. package/package.json +7 -8
  48. package/templates/node/package.json +1 -1
  49. package/dist/operator-ui/agents.d.ts +0 -75
  50. package/dist/operator-ui/agents.js +0 -114
  51. package/dist/operator-ui/config-summary.js +0 -566
  52. package/dist/operator-ui/connection-map.js +0 -378
  53. package/dist/operator-ui/endpoints.js +0 -212
  54. package/dist/operator-ui/fix-prompts.d.ts +0 -18
  55. package/dist/operator-ui/fix-prompts.js +0 -79
  56. package/dist/operator-ui/health.js +0 -52
  57. package/dist/operator-ui/member-page.js +0 -97
  58. package/dist/operator-ui/overview.js +0 -126
  59. package/dist/operator-ui/setup-commands.js +0 -47
  60. package/dist/operator-ui/view.d.ts +0 -378
  61. package/dist/operator-ui/view.js +0 -631
  62. package/dist/providers/_shared/rest/dispatch.js +0 -21
  63. package/dist/providers/_shared/rest/tools.js +0 -592
@@ -426,7 +426,7 @@ client. A raw Worker stream established the runtime behavior; a custom auth
426
426
  provider returning a synthetic streaming 401 exercised Connecta's real admission
427
427
  wrapper. Each case had its own Connecta instance with one request permit and no
428
428
  queue. Health checks and subsequent MCP requests confirmed the same isolate ID.
429
- The [recorded observations](https://github.com/zackbart/connecta/blob/a0ac904513fac735582b4bc9c817a48300134328/scripts/probes/worker-disconnect-2026-09-25.json)
429
+ The [recorded observations](https://github.com/zackbart/connecta/blob/1ab92695f2636f904274d900ce209553358ff1f3/scripts/probes/worker-disconnect-2026-09-25.json)
430
430
  contain all twelve cases, including served flags and client-end timing.
431
431
 
432
432
  | Response and flag | Raw stream abort / cancel | Connecta source abort / cancel | Admission after response; next request |
@@ -486,23 +486,23 @@ MCP requests still rejected a competing request with 503 before the deadline;
486
486
  the first MCP request after the deadline returned all eight tools with 200 in
487
487
  the original isolate. Admission then reported zero active requests. Without the
488
488
  flag, the source still recorded no abort or cancellation, so recovery did not
489
- rely on runtime cleanup. The [recovery observations](https://github.com/zackbart/connecta/blob/32d8e94/scripts/probes/worker-disconnect-recovered-2026-09-25.json)
489
+ rely on runtime cleanup. The [recovery observations](https://github.com/zackbart/connecta/blob/1ab92695f2636f904274d900ce209553358ff1f3/scripts/probes/worker-disconnect-recovered-2026-09-25.json)
490
490
  also retain two inconclusive queue-handoff cases: concurrent client connections
491
491
  reached different isolates and could not establish an abandoned queued waiter.
492
- A [second trial using HTTP/2](https://github.com/zackbart/connecta/blob/b174812/scripts/probes/worker-disconnect-h2-2026-09-25.json)
492
+ A [second trial using HTTP/2](https://github.com/zackbart/connecta/blob/1ab92695f2636f904274d900ce209553358ff1f3/scripts/probes/worker-disconnect-h2-2026-09-25.json)
493
493
  repeated the twelve passing core cases and verified queued cancellation with
494
494
  request signals enabled. Even on one HTTP/2 connection, the no-signal queue case
495
495
  crossed isolates and remained inconclusive. The Node and workerd regression
496
496
  suites cover expired waiters, orphaned handoffs, and identity-safe late release
497
497
  deterministically.
498
498
 
499
- To repeat from a repository checkout, run
500
- `node scripts/probes/worker-disconnect.mjs` with an authenticated Wrangler.
501
- The script is not in the npm package. It deploys a disposable Worker containing
502
- only synthetic data, verifies the served configuration, saves observations under `eval/results/`,
503
- and deletes the Worker in `finally`. It uses no `waitUntil`, which would change
504
- the lifetime being measured. The production runtime build number was not
505
- exposed by the deployment; these findings are tied to the date and flags above.
499
+ The [historical probe source](https://github.com/zackbart/connecta/blob/1ab92695f2636f904274d900ce209553358ff1f3/scripts/probes/worker-disconnect.mjs)
500
+ and observations are retained in Git history, outside the current checkout and
501
+ npm package. The probe deployed a disposable Worker containing only synthetic
502
+ data, verified the served configuration, saved observations, and deleted the
503
+ Worker in `finally`. It used no `waitUntil`, which would change the lifetime
504
+ being measured. The production runtime build number was not exposed by the
505
+ deployment; these findings are tied to the date and flags above.
506
506
 
507
507
  ### Production Access bypass for agent endpoints
508
508
 
@@ -1324,14 +1324,15 @@ A composition moves only by explicit review of its source pins/documents;
1324
1324
  `--record` and `--file` cannot replace it. `providers:check` compares the actual
1325
1325
  public documents independently; it never fetches a synthetic combined URL.
1326
1326
 
1327
- The generic REST connector (`src/providers/_shared/rest/`) serves
1327
+ The indexed hatch (`src/http/hatch.ts`) serves
1328
1328
  `<vendor>_api_search`, `_api_details`, `_api_read`, and `_api_write` over an
1329
1329
  `OperationIndex` that `pnpm run providers:spec` compiles offline from the
1330
- provider's pin (`evidence/openapi.json`; `openapi.source.json` until its step 1)
1331
- into `openapi.generated.ts`. A `vendored: true` pin compiles the reviewed
1332
- conversion in `evidence/openapi.document.json` instead of fetching, and the
1333
- generated header records that document's digest beside the pin's, so the
1334
- offline freshness check sees a changed conversion.
1330
+ provider's pin (`evidence/openapi.json`)
1331
+ into `openapi.generated.ts`. A `vendored: true` pin compiles offline from
1332
+ the reviewed conversion in `evidence/openapi.document.json`, or derives a
1333
+ deterministic Discovery conversion from its pinned original as described below.
1334
+ The generated header records the converted document's digest beside the pin's,
1335
+ so offline freshness sees a changed conversion.
1335
1336
  Each call is matched to an operation and checked against its parameters before
1336
1337
  transport. Resolved path parameters are validated before authentication or dispatch,
1337
1338
  including pinned enums and numeric bounds. Number path values must decode to canonical finite ASCII decimals without
@@ -1340,16 +1341,24 @@ canonical ASCII decimal safe integers: `0`, positive decimals without leading
1340
1341
  zeros, or negative decimals without leading zeros. `-0`, leading `+`, whitespace,
1341
1342
  exponents, decimal points and non-ASCII digits are refused. Negative integers
1342
1343
  remain valid when the pin has no minimum excluding them. String-valued ids keep
1343
- their declared string contract; `_api_read` admits GET and the vendor's reviewed read-only POSTs in
1344
- its handler, since classification is per tool name. Vendors configure only a
1345
- transport, failure mapper, scope, framing, cursor extraction, a reviewed
1346
- value-safety table (required; see below), argument-dependent refusals, and an
1347
- idempotency header, plus optional hooks: `path` (fill default ids before
1348
- matching), `admit` (an awaited check in `callRest` every tool passes, such as
1349
- Cloudflare's account and zone pin), `result` (unwrap a vendor envelope;
1350
- redaction runs after it and before cursors and `select`), a reviewed
1351
- request-header allowlist, text bodies, and index `slashParams` that admit an
1352
- encoded `/` in a final key segment (`test/rest-connector.test.ts`).
1344
+ their declared string contract. `_api_read` admits only operations with explicit
1345
+ reviewed read verdicts, including GET/HEAD and read-only POSTs where declared;
1346
+ classification is per tool name. Providers declare a confined kit connection,
1347
+ a value-safety table (required;
1348
+ see below), and any framing, scope, paging or refusal hooks through the hatch
1349
+ binding. The connection owns authentication, transport, failure mapping and
1350
+ result safety. An index's `slashParams` can admit an encoded `/` in a reviewed
1351
+ final key segment. Current hatch admission, paging, privacy and one-send
1352
+ outcomes are exercised by the required `eval:outcomes` tasks against stateful
1353
+ vendors and HTTP MCP deployments. `test/provider-hostile-response.node.test.ts`
1354
+ commits real HTTP writes before returning HTML, malformed JSON or an oversized
1355
+ acknowledgement, then reconciles vendor state with exactly one physical send.
1356
+ `test/provider-privacy-journey.node.test.ts` checks credential echoes over HTTP.
1357
+ Focused provider suites retain MIME/draft restrictions, revision conflicts,
1358
+ 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.
1361
+ No legacy REST tool adapter remains.
1353
1362
  Large documents opt into generator options that drop restated operation ids
1354
1363
  and plain path parameters and cap one operation's details (`opBudget`).
1355
1364
  `numericBounds: true` preserves documented numeric minimum/maximum constraints
@@ -1364,8 +1373,7 @@ levels, 256 paths or 200 characters per path; overflow or an unresolved
1364
1373
  reference omits that operation's whole response-field contract. Explicitly open
1365
1374
  roots (including root-array items) also leave fields absent. Empty,
1366
1375
  schemaless and non-JSON responses declare no fields. Request shrinking and
1367
- endpoint contract digests do not depend on this metadata. Legacy REST tools
1368
- retain their catalog and discovery behavior until each provider's step 2.
1376
+ endpoint contract digests do not depend on this metadata.
1369
1377
  Fields remain optional additive metadata, so a previously compiled
1370
1378
  index without the source bytes remains usable without inventing a response
1371
1379
  contract. Vercel's step-2 pin review restores response metadata from the reviewed public
@@ -1406,7 +1414,7 @@ UTF-16 code units; full reconstruction must match its recorded exact length.
1406
1414
  These physical decode checks do not change request validation, schema traversal,
1407
1415
  search, refusal, result or discovery budgets. Generation and offline roundtrip
1408
1416
  tests must preserve every pinned logical contract; storage changes never accept
1409
- new upstream evidence or golden bytes. The compaction suites cover exact strings,
1417
+ new upstream evidence. The compaction suites cover exact strings,
1410
1418
  native Web Crypto identity, malformed references, lazy decoding, mutation
1411
1419
  semantics and every maintained provider.
1412
1420
 
@@ -1455,8 +1463,8 @@ every vendor ships one reviewed table through one mechanism
1455
1463
  otherwise. `providers:spec` derives the binding fields from the pinned
1456
1464
  schema, and the harness fails until the condition lists each one. Argument-dependent refusals (Stripe expansions,
1457
1465
  Vercel `decrypt`) stay in the vendor's `refuse` hook.
1458
- 3. **Redaction on every success body**, in `callRest` after `result` and
1459
- before cursors and `select`, so named tools, HEAD data, and uploads pass
1466
+ 3. **Redaction on every success body**, in the kit connection after `result`
1467
+ and before cursors and `fields`, so named tools, HEAD data, and uploads pass
1460
1468
  through it too: the operation's reviewed paths, then the key-name
1461
1469
  heuristic as defense in depth. The heuristic is the union of the former
1462
1470
  vendor engines: a credential word anywhere in a non-metadata name removes
@@ -1653,232 +1661,50 @@ There are no hosted review maps, pins, drift comparisons or review UI fields.
1653
1661
  Catalog refresh activity still compares successive accepted catalog fingerprints
1654
1662
  and reports only added, removed and changed counts in the caller's partition.
1655
1663
 
1656
- #### Characterization goldens
1657
-
1658
- Every maintained provider with an `api()` surface has goldens under
1659
- `test/goldens/<provider>/`: the oracle a provider migration must match byte
1660
- for byte. `catalog.json` holds the connector metadata, the rendered guide,
1661
- and each tool's name, description, schemas, and annotations. `calls.json`
1662
- holds at least one fixture call per tool, then an echo call: the exact
1663
- requests sent (method, URL, sorted headers, body), grouped into causal
1664
- steps, and the agent-visible outcome. `failures.json` drives one read and
1665
- one write through 400, 401, 403, 404, 409, 422, 429 (with `retry-after`)
1666
- and 500 responses, a 401 whose message echoes every sent secret, a refused
1667
- connection, and a transport timeout (a `TimeoutError` after the request
1668
- left). `setup.json`, for a provider whose spec completes an OAuth consent,
1669
- holds the consent's steps. Calls run through `Registry` and
1670
- `InvocationService` with a real credential vault, so the outcome is what
1671
- `call_tool` returns before MCP rendering.
1672
-
1673
- `test/goldens/<provider>/spec.ts` says only how to build the provider and
1674
- which calls to make, including an `echo` call whose vendor reply carries the
1675
- text the harness passes. `test/goldens/harness.ts` owns everything else:
1676
-
1677
- - The fake network records each request as `new Request(input, init)`
1678
- builds it, so `init.headers` replaces a Request's headers as Fetch does,
1679
- and a body gets its implied `content-type`. Form bodies are recorded as
1680
- fields when they re-encode to the exact bytes sent; FormData as its parts,
1681
- with the runtime's boundary as `<boundary>`. A JSON body is recorded as
1682
- `json` alone only when it is exactly that value's compact serialization;
1683
- any other spacing, key order, or escape also keeps the exact `text`.
1684
- - A step loop drives each scenario under fake timers. It drains microtasks,
1685
- fires timers due now synchronously, and waits for request construction and
1686
- counted real work to finish. Newly waiting requests form one step, sorted
1687
- by method, URL, headers, and exact body. The loop releases **one answer at
1688
- a time**, running to quiescence after each. Previously recorded requests
1689
- keep release priority over new requests. Fixture updates capture canonical
1690
- cohort release order and reverse cohort release order, each with its own
1691
- fresh module graph, clock, network and cache namespace. Queue replies are
1692
- assigned in canonical request order in both runs; only answer delivery
1693
- changes. Steps remain readable admission cohorts, not simultaneous answers.
1694
- Workerd checks compare the canonical observation. In stored fixtures,
1695
- identical observations collapse to one
1696
- row; differing reverse observations appear in `variants`, each with
1697
- `order: "reverse"`, complete `steps`, optional `waitedMs`, and `result`.
1698
- Setup uses the same rule, with `{ steps, variants }` only when orders differ.
1699
- This bounded two-order model deliberately does not enumerate all interleavings.
1700
- - Every request records integer `after`: the number of answers delivered
1701
- when the provider called fetch, before harness jitter or body inspection.
1702
- It identifies a prefix of that run's release sequence; it includes auxiliary
1703
- requests and resets for setup and invocation. The canonical run releases
1704
- each cohort forwards, the reverse run backwards, with older cohorts first.
1705
- For concurrent A and B, C awaiting only B and C awaiting both have canonical
1706
- `after: 2`, but reverse `after: 1` and `after: 2` respectively. The differing
1707
- variant preserves that dependency. One integer per request keeps frontiers
1708
- linear, including a 300-page sequential call. A write sent before login and
1709
- a write duplicated concurrently or sequentially also differ.
1710
- - Distinct queued replies for indistinguishable concurrent requests are a
1711
- fixture authoring error: the harness rejects them with a diagnostic. Use
1712
- identical replies or a request discriminator the provider controls. The
1713
- arrival order of identical requests cannot assign distinct responses.
1714
- - `test/goldens/setup.ts` installs source dispatchers before a golden test
1715
- file imports any provider, connector or Effect module. `vi.resetModules()`
1716
- and dynamic imports refresh those graphs for each capture and release order.
1717
- The dispatchers retain their identity across captures: saved and prebound
1718
- functions, and functions captured by Effect, still consult the current
1719
- capture. Their defining prototypes are wrapped too. Native implementations
1720
- remain private to the source controller; outside captures the dispatchers
1721
- delegate unchanged, preserving Vitest's real clocks and runner timeouts.
1722
- - The supported asynchronous model is explicit: fake fetch answers; fake
1723
- timeout, interval and immediate timers, including `AbortSignal.timeout`; Web Crypto's promise-returning
1724
- subtle methods; Request/Response/Blob body reads (`arrayBuffer`, `blob`,
1725
- `bytes`, `formData`, `json`, `text`, where present); default stream-reader
1726
- `read`/`cancel` and stream `cancel`/`pipeTo`; and promises/`queueMicrotask` chains rooted in those sources or
1727
- synchronous work. Effect's scheduler and sleeps use the same microtasks
1728
- and fake timers. A synchronous TextDecoderStream pipeline is supported.
1729
- Timer delays must coerce to finite nonnegative integer milliseconds within
1730
- the signed 32-bit timer range; other delays poison the capture. This keeps
1731
- Date and nanosecond clocks integral. New host asynchronous sources must be
1732
- registered and counted before use.
1733
- Native CompressionStream/DecompressionStream, `scheduler.wait`, and
1734
- native socket/worker/event-source constructors are rejected explicitly,
1735
- including when their errors are swallowed by a provider. CompressionStream
1736
- async iteration bypasses the reader-method spy and cannot establish
1737
- quiescence. No golden may silently bless that path.
1738
- - A no-stimulus audit follows declared quiescence: request, counted-work,
1739
- timer, or call-settlement progress before an answer or clock tick fails
1740
- with an unsupported-source diagnostic. Waiting without a request, counted
1741
- work, or fake timer also fails. The audit is a secondary assertion: source
1742
- control starts at module load, and supported host promises and microtasks
1743
- are counted from entry through completion. Quiescence requires zero active
1744
- counted work, zero queued controlled microtasks, and no due timers; future
1745
- virtual timers are explicit harness stimuli. Unregistered native producers
1746
- are unavailable or throw, including saved constructors and swallowed errors.
1747
- `process.nextTick`, `process.uptime`, `Atomics.waitAsync`, native messaging
1748
- constructors, and performance timeline methods are unsupported. The
1749
- test-only `golden-source-boundary` transform rejects Node host-module imports
1750
- in provider graphs and rejects lazy module loading during scenario work,
1751
- before either can capture native references or schedule uncounted I/O. Only
1752
- the harness's fresh-graph loading phase admits test fixture imports.
1753
- Invalid captures cancel and drain their concurrent fake requests.
1754
- - Settle, rejected-capture cleanup, and final teardown pump controlled timers,
1755
- microtasks, and fake requests within the original 10,000-host-turn windows.
1756
- Only outstanding captured Web Crypto operations can extend a window: after
1757
- exhausting it, await a snapshot of those native operations to settle, then
1758
- resume with a fresh bounded window. Each phase allows at most 100 native
1759
- extensions and reports an explicit error on exhaustion. Web Crypto always
1760
- settles independently of the harness's fake network, timers, and producers.
1761
- Body reads and stream reads are counted for quiescence but cannot extend a
1762
- window: their producers may require a fake response, future virtual time,
1763
- or never complete. No producer attribution or stream constructor tracking
1764
- is needed. Pending native crypto never advances virtual deadlines or merges
1765
- request cohorts. Clock advancement remains limited to 1,000 ticks.
1766
- Unsupported producer dependencies reject within the turn bound; teardown
1767
- always clears timers and releases capture ownership, including after failed
1768
- construction and overlapping capture rejection. The next capture must work.
1769
- Each capture has an async-context epoch that closes before ownership is
1770
- released, even when its native extension cap is exhausted. Controlled-source dispatchers reject closed
1771
- continuations before touching another capture's state. Fake request entry,
1772
- admission, response delivery, and serialization check their owning epoch,
1773
- including after asynchronous body inspection. Late work cannot record into
1774
- or receive a response from a later capture, which never waits for it.
1775
- Closing also attaches rejection handlers to outstanding counted promises,
1776
- consuming abandoned native body-read rejections without awaiting them.
1777
- Source regressions explicitly assert either completion or bounded rejection
1778
- followed by recovery. Crypto-delay probes at 11,000 and 100,000 host turns
1779
- must complete with unchanged observations; producer-fed bodies need not.
1780
- - The network answers in zero virtual time. Before advancing to the next
1781
- timer, the loop requires eight quiet real event-loop turns and an audit.
1782
- A row records nonzero `waitedMs`, the virtual time spent on provider
1783
- timers. Elapsed-time readings count only those timers. A timer of 0 ms
1784
- set outside a timer callback is due at once and stays in the current
1785
- cohort. Unjoined timers at completion fail. Since `AbortSignal.timeout`
1786
- cannot be cancelled, remaining signal deadlines fire during teardown, outside
1787
- `waitedMs`; any resulting request or result mutation fails. Every successful
1788
- drive and scenario boundary has zero outstanding controlled work and timers.
1789
- - Auxiliary routes answer token exchanges and other requests that are not
1790
- the tool's own, and are recorded by name with headers and body. A JWT in a
1791
- header or field is recorded as its decoded header and claims, with
1792
- `<signature>` for the per-run signature.
1793
- - `setup` runs before each scenario; its requests must be identical in
1794
- every scenario and are recorded once.
1795
- - Determinism: a fresh fake clock per scenario (timers, `Date`, and
1796
- `performance`, and Node `process.hrtime`/`hrtime.bigint`, starting at
1797
- 2026-01-02T03:04:05Z), counted
1798
- `crypto.randomUUID`, and fixed `crypto.getRandomValues` and `Math.random`,
1799
- all restarted per scenario. `create(scenario)` receives a slug unique in
1800
- the process: the scenario name plus a per-capture suffix the goldens never
1801
- show. Load-time hrtime dispatchers also control Effect wall and monotonic
1802
- nanoseconds on the virtual clock. Default-date Intl formatting also reads
1803
- the virtual wall clock.
1804
- A process-wide cache (Google's delegated tokens) never carries
1805
- over from an earlier scenario or capture.
1806
- - Secrets: every credential field and secret becomes `<secret:field>`, with
1807
- HTTP Basic shown decoded. Before that placeholdering, the harness fails
1808
- the capture if any secret reaches a caller-visible result (INV-5). The
1809
- guard decodes the result itself: JSON escapes, percent escapes in either
1810
- hex case, and base64 or base64url at any alignment, up to three layers
1811
- deep. It also finds any start of a secret that reaches 12 characters past
1812
- its public framing, so a truncated echo is a leak. Framing is a PEM armor
1813
- line and the DER structure that opens every key of its type (tags,
1814
- lengths, version, algorithm identifier), which guides and example keys
1815
- print. A later fragment, a shorter one in any encoding, or a secret with
1816
- its case changed is not detected. A base64 run is decoded only from 11
1817
- characters (8 bytes), shorter than the base64 of any start the guard
1818
- looks for.
1819
- - The echo call carries every secret not listed in `unsent` in each
1820
- encoding redaction covers: raw, percent-encoded with upper- and lowercase
1821
- hex, base64, unpadded base64url, and `\uXXXX` escapes with upper- and
1822
- lowercase hex, plus the base64 of each `basic` pair. Every sent secret
1823
- contains `/`, `+`, and `=`, so its percent and base64url forms differ from
1824
- its raw and base64 forms. The `401 echo` case echoes the raw secrets only
1825
- unless the spec sets `errorEcho: "all"`: a provider that caps a vendor
1826
- message before redaction sees it would leak the start of a longer form its
1827
- cut goes through. The Google Workspace specs set it, since Google redacts a
1828
- message whole before cutting it to 500 characters. Their `401 echo` carries
1829
- `errorEchoForms`: every form above, the `Bearer` and `token` framings, and
1830
- an HTTP Basic pair holding the token as header, base64 and base64url.
1831
-
1832
- Object keys keep the order the provider produced. A migration changes the
1833
- provider, never the spec or harness.
1834
-
1835
- `test/goldens.test.ts` compares every provider on Node and workerd. It fails
1836
- if a provider folder is neither covered nor listed as remote-MCP-only, a tool
1837
- has no call, or a golden file is missing or extra. Ordinary checks never write.
1838
- Node compares forward and reverse observations byte for byte; workerd compares
1839
- canonical observations. Each order starts a fresh module graph. Workers projection
1840
- removes variants only at harness observation positions, never from vendor fields
1841
- or schemas. Fixture updates retain both orders.
1842
- There are no characterization tiers, path classifiers, or planning-only runs.
1843
-
1844
- `test/goldens-harness.test.ts` keeps the source and mutation guards on Node:
1845
- replaced Authorization headers, changed auxiliary/login bytes, writes sent
1846
- early or twice, and missing secret-encoding redaction must alter a capture or
1847
- fail it. Mutation probes capture the affected call rather than repeating an
1848
- entire provider catalog. Redaction negative controls use Forms, GitHub, Breeze
1849
- and Tithe.ly to cover OAuth/Bearer, app-token, query-key and provider-kit lanes;
1850
- the ordinary goldens still check every provider's complete secret echoes.
1851
- The native-extension budget is checked directly at its 100-extension boundary,
1852
- and a gated closed-epoch continuation must fail before entering the next
1853
- capture's network. Genuine crypto completion, rejection, late dispatch and
1854
- producer-fed stream probes retain their native settlement coverage without
1855
- repeating a million-turn synthetic delay. Ordinary runs use one source-probe schedule. Nightly Node runs set
1856
- `CONNECTA_GOLDENS_DETERMINISM=1` for an identical repeat, provider jitter seeds
1857
- 1 and 2, and the complete source-probe jitter matrix. Small native-source probes also run on
1858
- workerd: `scheduler.wait`, CompressionStream, saved timers/microtasks and
1859
- Effect scheduling, prebound crypto/clocks, module freshness, runner clocks,
1860
- and Blob/TextDecoderStream promise settlement. Runtime-specific cases carry
1861
- Vitest's `workers` tag; broad cases carry `node`, which the Workers project
1862
- skips. Other mixed transport/auth/runtime suites use the same tags to retain
1863
- native fetch, request/response streams, deadlines, signals, crypto and SDK
1864
- settlement without duplicating their policy matrices. `vitest.config.ts`
1865
- selects these files with globs that tolerate test-file deletion. Portable
1866
- filenames alone do not enroll a new file in workerd.
1867
-
1868
- Repository verification policy, CI requirements, and exact commands live in
1869
- [AGENTS.md](https://github.com/zackbart/connecta/blob/main/AGENTS.md#verification).
1870
-
1871
- JWT fixture specs import fixed, public throwaway RSA PEM keys, with an
1872
- import/sign/verify self-test. This avoids expensive key generation on every
1873
- fresh module evaluation without changing characterized JWT claims or bytes.
1874
- The harness never caches evaluated module graphs. Global controls prohibit
1875
- `it.concurrent`; parallelism must use isolated files/workers. Transformed code
1876
- may be cached.
1877
-
1878
- `pnpm run goldens:update [provider...]` rewrites the named goldens (all
1879
- when none are named) on Node; it is not part of `check`. A PR
1880
- that changes agent-facing output on purpose regenerates the affected goldens
1881
- and says why in its description; any other golden diff is a regression.
1664
+ #### Behavioral evidence (contributor)
1665
+
1666
+ The characterization snapshot engine, provider JSON snapshots, source scheduler
1667
+ and its self-tests are retired under
1668
+ [#1072](https://github.com/zackbart/connecta/issues/1072). Provider changes no
1669
+ longer require golden enrollment, snapshot updates, byte equivalence or nightly
1670
+ capture determinism. Production invariants remain unchanged.
1671
+
1672
+ Use the existing stateful fixture vendors and published-edge deployment adapters:
1673
+
1674
+ - `pnpm run eval:outcomes` drives representative joins, retained paging, endpoint
1675
+ refusal, auth handoff, value safety and refund recovery. Graders inspect
1676
+ independent downstream state and the physical mutation ledger, and reject
1677
+ wrong targets, duplicate writes, missing completion and interrupted trials.
1678
+ - `pnpm run eval:smoke` boots the Node template, Node eval deployments and native
1679
+ Workers deployments, including the actual QuickBooks provider, then exercises
1680
+ MCP and the operator page.
1681
+ - `test/provider-privacy-journey.node.test.ts` sends credentials through real
1682
+ HTTP MCP and a maintained API provider. Unknown vendor fields and keys carry
1683
+ raw, escaped, percent-encoded, base64 and Basic echoes through direct calls,
1684
+ QuickJS programs, failure and recovery. The independent decoder in
1685
+ `test/helpers/secret-echoes.ts` checks the wire responses for secret fragments;
1686
+ 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
1690
+ `test/sent-secrets.test.ts`, `test/sent-secret-output-boundary.test.ts`,
1691
+ `test/request-secret-redaction.test.ts` and `test/catalog-secret-redaction.test.ts`
1692
+ cover secrecy before projection, truncation, caching, paging and diagnostics.
1693
+ - `test/write-evidence.node.test.ts`, `test/remote-mcp-attempts.node.test.ts` and
1694
+ `test/oauth-credential-attempts.node.test.ts` inspect physical socket sends.
1695
+ Native transport parity, OAuth and write-provenance suites retain their
1696
+ workerd coverage. The shared throwaway RSA key in `test/fixtures/rsa.ts` is
1697
+ used by write-provenance and unknown-write-advice fixtures.
1698
+ - The request, catalog, auxiliary-call, renewal and Promise-boundary lifetime
1699
+ suites, plus `test/auth-admission-binding.test.ts`, exercise cancellation,
1700
+ held native work and garbage collection. These test actual request ownership;
1701
+ the retired capture scheduler's source guards were only harness constraints.
1702
+
1703
+ Add a compact fault journey only for a meaningful outcome those suites cannot
1704
+ observe. Reuse their fixtures and adapters; do not reintroduce a snapshot
1705
+ format, module loader or virtual scheduler. Workerd enrollment is for native
1706
+ fetch, streams, Web Crypto, lifetime and request-byte behavior, as listed in
1707
+ `vitest.config.ts`; pure logic runs on Node.
1882
1708
 
1883
1709
  ## Optional deployment modules
1884
1710
 
@@ -2152,8 +1978,7 @@ never-settling evaluation/host calls, late rejection, execute-once ownership and
2152
1978
  original acquisition errors in workerd. `test/quickjs-pool.node.test.ts` covers
2153
1979
  readiness release, stale/malformed IPC, late host failures, backoff and bounded
2154
1980
  kill. Real Worker and QuickJS guest contracts, the HTTP Worker budget/queued
2155
- request fixture and native-output suites supply runtime parity evidence;
2156
- provider goldens do not execute a sandbox.
1981
+ request fixture and native-output suites supply runtime parity evidence.
2157
1982
 
2158
1983
  ### Native SQL storage (contributor)
2159
1984
 
@@ -2283,9 +2108,12 @@ An accepted write's blocked retry retains its original HTTP status; a slot
2283
2108
  occupied by an auxiliary read instead names the separate write step needed.
2284
2109
  Structured resend advice reaches output only when the core permits it. Generic
2285
2110
  unknown writes retain the core's diagnostic wait; Q8 removes it. The mapping
2286
- adds no Promise entry or lifetime owner. The rule tables in `http-kit.test.ts`,
2287
- Stripe's sixteen-branch comparison and `kit-core-verdicts.test.ts` establish
2288
- these internal contracts. Maintained API providers use the kit through their
2111
+ adds no Promise entry or lifetime owner. `provider-failure-sweep.test.ts`,
2112
+ `guarded-attempts.node.test.ts`, `call-services.test.ts` and the native
2113
+ transport suites exercise these contracts through invocation, physical sockets
2114
+ and request closure. `http-kit.test.ts` retains focused numeric/text fact,
2115
+ request-equivalence and bulk-capacity fault probes. The migration-era
2116
+ kit/core verdict comparison is retired under #1072. Maintained API providers use the kit through their
2289
2117
  explicit provider subpaths; it stays off the root import graph and published
2290
2118
  declarations expose Promises.
2291
2119
 
@@ -2364,12 +2192,11 @@ inventories, and stale fallback cannot authorize post-entry auth recovery.
2364
2192
  ### Contributor provider kit
2365
2193
 
2366
2194
  Provider declarations use `src/http/vendor.ts` for HttpApi operations and
2367
- `src/http/tools.ts` for list, get, read, write and action builders.
2195
+ `src/http/tools.ts` for list, get, read and write builders.
2368
2196
  `src/http/provider.ts` composes them with `defineProvider`; it returns the
2369
2197
  ordinary Promise-based Connector factory. The kit stays outside the root
2370
- graph and its Effect types are internal. Tithe.ly is the first provider on
2371
- it (B.5): `api.ts` declares the vendor, `tools.ts` the tools, and its goldens
2372
- are unchanged.
2198
+ graph and its Effect types are internal. In each provider, `api.ts` declares
2199
+ the vendor and `tools.ts` the tools.
2373
2200
 
2374
2201
  Decision 0011's standard surface (Tithe.ly's step 2) adds four kit pieces.
2375
2202
  A `list` without the legacy `key` returns `{ items, page }`, with
@@ -2460,7 +2287,7 @@ A refused method outside a read/write tool's input schema is inspected through
2460
2287
  Gmail's 49 non-GET refusals do not add a method field or a write hatch, and Forms'
2461
2288
  refused DELETE remains outside its write enum. GitHub's refused raw PUT merge
2462
2289
  is likewise outside its write enum; its named guarded alternative is unaffected.
2463
- These 51 schema refusals happen
2290
+ Such schema refusals happen
2464
2291
  before authentication or I/O; details exposes the same reviewed reason as search.
2465
2292
  Every schema-reachable refused operation still fails with that reason before
2466
2293
  authentication or dispatch. This is policy inspection, never execution admission.
@@ -2611,8 +2438,7 @@ storage loses them with the store. Key-load outages or corrupt stored keys
2611
2438
  produce retryable `unavailable`, naming the cursor signing key without its
2612
2439
  value. See [cursor-key recovery](./deploying.md#recover-a-cursor-signing-key):
2613
2440
  after repairing/deleting a corrupt key, restart every process/isolate to clear
2614
- cached keys. Pre-upgrade cursors require a new first page. Offline goldens
2615
- preseed a fixed key only in their harness.
2441
+ cached keys. Pre-upgrade cursors require a new first page.
2616
2442
 
2617
2443
  The helper derives connection metadata and probe messages from
2618
2444
  validated options and still accepts complete legacy usage guides for compatibility.
@@ -2624,8 +2450,7 @@ CCB uses shared System Auth grants and personal Identity Auth grants. Tool
2624
2450
  arguments cannot select a grant's owner. On Node, every maintained-provider
2625
2451
  request uses the owned sender `listen()` installs, reads included. Without it,
2626
2452
  maintained-provider writes and reviewed POST reads are refused before sending;
2627
- suites exercising those requests configure the sender themselves, as the goldens
2628
- harness does. Anything a connection
2453
+ focused suites exercising those requests configure the sender themselves. Anything a connection
2629
2454
  caches across calls, such as its typed HttpApi client, is built with no
2630
2455
  services, because Effect constructors close over the context they run in and a
2631
2456
  cached value would otherwise keep its first caller's request alive (INV-7).
@@ -2669,8 +2494,20 @@ All six Google Workspace products use the shared standard-surface support.
2669
2494
  archived exact-byte official Discovery documents into deterministic OpenAPI.
2670
2495
  The primary vendored pin retains the official URL, revision and source digest;
2671
2496
  its `discovery` relation names the sibling source pin and normalizer format.
2672
- Generation and offline freshness reproduce the conversion, and the generated
2673
- module records its independent document digest. Full source method inventory
2497
+ The sole retained document is `evidence/discovery.document.json`; no converted
2498
+ `openapi.document.json` is retained for these pins. Generation and offline
2499
+ freshness validate the original bytes against `discovery.json` and the primary
2500
+ pin, then derive the conversion in memory, including reviewed summary overrides.
2501
+ Its digest uses two-space JSON indentation and a terminal newline; the generated
2502
+ module records that independent document digest, preserving freshness checks
2503
+ for changes to the normalizer or summaries. This supersedes Decision 0011's
2504
+ retained-conversion requirement for deterministic Discovery evidence. Frozen
2505
+ measurements read those same provider-owned originals but validate the existing
2506
+ `test/fixtures/google-discovery/manifest.json` digests independently: a provider
2507
+ pin update must fail the historical measurement rather than silently rebase it.
2508
+ That reviewed pin-change PR must re-measure and update the product's manifest
2509
+ entry and the Forms #1009 drift-check digests when applicable, or retire the
2510
+ measurement. Full source method inventory
2674
2511
  and canonical source-to-relative-path mappings survive normalization. Gmail's
2675
2512
  source `userId` becomes deployment-owned `me`; runtime paths are relative to
2676
2513
  the existing connection root. Reserved Slides ids remain one encoded segment.
@@ -2692,13 +2529,13 @@ independent batch-kind, revision and resource guards. Google indexes explicitly
2692
2529
  set `pathMatching: "uri-template"` on `OperationIndex` to handle encoded literal
2693
2530
  collisions and parameter action suffixes. Other indexes retain exact literal
2694
2531
  segments and their existing refusal ordering. The matching mode also binds
2695
- discovery cursors. An indexed `googleClient` requires each named request's declared
2696
- template and refuses a substituted id resolving to another operation before
2697
- grant evaluation. Products opt in with `googleClient(connection, title,
2698
- { standard: true, index })`; their requests carry `template`.
2532
+ discovery cursors. `googleClient(connection, index)` requires each named request's
2533
+ declared `template` and refuses a substituted id resolving to another operation
2534
+ before grant evaluation. Every maintained Google product uses this indexed
2535
+ client; there is no unindexed settlement mode.
2699
2536
  Both the client and `googleHatchBinding(connection, { index, review })` require
2700
2537
  the explicit URI-template mode at construction. The hatch requires the binding's
2701
- exact index identity. Standard clients and Google bindings reject a missing
2538
+ exact index identity. Clients and Google bindings reject a missing
2702
2539
  index with an explicit construction error. The provider-standard suite checks
2703
2540
  actual hatch construction through every Google product fixture, requiring its
2704
2541
  Google binding with the same connection and index. The Google binding
@@ -2739,12 +2576,12 @@ provider, not a claim that the Forms migration has shipped.
2739
2576
 
2740
2577
  `googleErrors(product, { standard: true })` declares the product's 404 meaning
2741
2578
  and uses common status fallbacks; revision-conflict meanings require a
2742
- separate declaration. Standard-mode `googleClient` preserves failure phase
2579
+ separate declaration. `googleClient` preserves failure phase
2743
2580
  metadata for partial-create recovery while leaving settlement and wording to
2744
2581
  the kit. Its incomplete-body wording covers JSON and binary reads without
2745
- claiming that binary success was expected to be JSON. Legacy mode retains
2746
- its catalog and failure bytes. No shared-core auxiliary-write outcome change
2747
- is part of this opt-in support.
2582
+ claiming that binary success was expected to be JSON. `googleGrant` still uses
2583
+ the nonstandard `googleErrors(product)` mapping for delegated-token rejection;
2584
+ that grant contract is separate from resource-request settlement.
2748
2585
 
2749
2586
  Drive's two-request reads also declare fixed steps: `get_file_content` uses
2750
2587
  `metadata` and `content`, and non-root `list_folder_items` uses `folder` and
@@ -2755,10 +2592,8 @@ Gmail declares separate initial and body-download steps for `get_message`,
2755
2592
  each of up to 25 summary reads, and `get_thread` names each stored body in
2756
2593
  Gmail's 100-message conversation limit. Serving these reads as writes keeps
2757
2594
  every request available once.
2758
- The layer's request adapter keeps the legacy wording of a served write whose
2759
- answer proves nothing (no answer, a 5xx, a redirect, or an unreadable 2xx) and
2760
- reports how far a failed request got. The core still decides every write's
2761
- outcome. Gmail's auxiliary draft and reply lookups pass both `effect: "read"`
2595
+ The request adapter reports how far a failed request got; the kit maps the
2596
+ failure and the core decides every write's outcome. Gmail's auxiliary draft and reply lookups pass both `effect: "read"`
2762
2597
  and a construction-declared step: the guarded client's early reservation uses
2763
2598
  that named slot, while the ledger marks the request auxiliary. A failed lookup
2764
2599
  keeps its read verdict and cannot make an unsent draft write unknown.
@@ -2801,10 +2636,8 @@ Every defect from a run probe or its hooks uses the generic withheld notice,
2801
2636
  even without a kit dispatch, because a private transport leaves no kit visibility
2802
2637
  evidence. An open operation probe retains its original defect.
2803
2638
 
2804
- The REST bridge in `src/providers/_shared/rest/kit.ts` retains pinned index
2805
- validation and legacy hatch schemas while the kit owns tool leases, fixed write
2806
- capacity, transport, failures and result safety. It verifies schema equality
2807
- before restoring legacy catalog key order. `indexedVendor` derives operation
2639
+ `src/providers/_shared/rest/kit.ts` owns the shared REST call shapes, pinned
2640
+ schema conversion and indexed vendor declarations. `indexedVendor` derives operation
2808
2641
  metadata from the index and builds the full manifest lazily; the typed client
2809
2642
  contains only named operations and probes. Bulk indexed declarations preserve
2810
2643
  the OpenAPI brace paths verbatim and carry explicit parameter Schemas. They
@@ -2828,7 +2661,7 @@ transport idempotency key. These hints describe behavior; write routing and
2828
2661
  endpoint restrictions still apply. For example, a tool that only creates a new
2829
2662
  note can declare `destructive:false` without promising idempotency.
2830
2663
 
2831
- `restKitTools` may declare a `writeSteps` map whose values are `"once"`.
2664
+ Kit tools and the indexed hatch may declare a `writeSteps` map whose values are `"once"`.
2832
2665
  Construction freezes the map; every named step sends at most once and an
2833
2666
  undeclared step is refused before dispatch. Omitting it retains the single
2834
2667
  implicit write step. Auxiliary ownership reads in a write call retain that
@@ -3089,10 +2922,10 @@ same version to resolve a single copy. Connecta's own lockfile and packed
3089
2922
  install are checked for one copy (`test/package-surface.node.test.ts` and
3090
2923
  `scripts/check-package.mjs`).
3091
2924
 
3092
- The stable `4.0.0` release was re-evaluated on 2026-10-01 with
3093
- [`scripts/probes/effect-v4-evaluation.mjs`](https://github.com/zackbart/connecta/blob/main/scripts/probes/effect-v4-evaluation.mjs).
3094
- Run `pnpm run build`, then `node scripts/probes/effect-v4-evaluation.mjs output.json`.
3095
- The [raw observations](https://github.com/zackbart/connecta/blob/main/scripts/probes/effect-v4-evaluation-2026-10-01.json)
2925
+ The stable `4.0.0` release was re-evaluated on 2026-10-01 with this
2926
+ [historical probe source](https://github.com/zackbart/connecta/blob/1ab92695f2636f904274d900ce209553358ff1f3/scripts/probes/effect-v4-evaluation.mjs),
2927
+ retained in Git history rather than the current checkout.
2928
+ The [raw observations](https://github.com/zackbart/connecta/blob/1ab92695f2636f904274d900ce209553358ff1f3/scripts/probes/effect-v4-evaluation-2026-10-01.json)
3096
2929
  are synthetic Node requests and neutral esbuild bundles, not live-client or
3097
2930
  workerd lifetime verification. Bundle figures add representative prototypes
3098
2931
  alongside the current code; they do not claim savings from removing old code.
@@ -3101,7 +2934,7 @@ Two native input schemas with validation and JSON Schema rendering add 62,148
3101
2934
  bytes gzip to the root, taking it from 303,083 to 365,231 against a 339,526
3102
2935
  cap. Effect can reject excess properties when both decoding and rendering use
3103
2936
  `onExcessProperty: "error"`; its default strips them. The generated schemas
3104
- still differ from the exact meta-tool goldens, including record rendering and
2937
+ still differ from the published meta-tool schemas, including record rendering and
3105
2938
  composed numeric bounds. A Schema replacement would need to preserve that
3106
2939
  contract and memoized rendering. Both MCP SDK packages still depend on Zod,
3107
2940
  so changing our inputs alone does not remove Zod from an installation.
@@ -3466,7 +3299,7 @@ compiling and configuring the real thing.
3466
3299
  (`keyProtectsLogicalCall`). Every resource request dispatched under the
3467
3300
  logical call, from any ledger, is recorded on it once per dispatch with
3468
3301
  its method and the genuine key it carried (`ProviderRequest.key`, set by
3469
- `callRest` only for a key fetch sends as given). The advice stands only when
3302
+ the kit's guarded transport only for a key fetch sends as given). The advice stands only when
3470
3303
  exactly one boundary was entered, the invocation's object owns it as for
3471
3304
  `knownForLogicalCall`, that boundary tracks every request, and exactly one
3472
3305
  dispatched request was a write, carrying the named key; a request counts as
@@ -3511,10 +3344,10 @@ compiling and configuring the real thing.
3511
3344
  reconciliation even with an idempotency key; direct transport calls
3512
3345
  without a served verdict can still prove repeatability, but only with a
3513
3346
  genuine key sent to a vendor that honors it (Stripe today, through
3514
- `idempotencyHeader`): the REST write tool refuses an `idempotencyKey` that fetch
3347
+ `hatch.idempotency`): the REST write tool refuses an `idempotencyKey` that fetch
3515
3348
  would send empty after trimming or would not send at all (CR, LF, NUL, any
3516
3349
  other control character but tab, DEL, or a code point past Latin-1), as
3517
- `invalid_args` before recovery is recorded, and `callRest` marks a request
3350
+ `invalid_args` before recovery is recorded, and the guarded transport marks a request
3518
3351
  repeatable only for a key fetch sends as given.
3519
3352
  `providerCallFailure` (`src/write-outcome.ts`) is the one finalizer for a
3520
3353
  direct write's failure: the `api()` handler boundary, a guarded transport
@@ -3542,7 +3375,7 @@ compiling and configuring the real thing.
3542
3375
  overrides with HTTP 503 for every tool and a connection reset after send
3543
3376
  for each provider/verdict representative. HTTP 401 recovery uses those
3544
3377
  representatives plus the distinct composite, auxiliary, owner-lookup and
3545
- POST-as-read paths; every provider's full golden failure matrix still runs.
3378
+ POST-as-read paths.
3546
3379
  Shared sender and real-socket evidence below own status/reset permutations.
3547
3380
  Local metadata
3548
3381
  tools prove zero sends; composite calls prove each distinct request leaves
@@ -3831,7 +3664,7 @@ and workerd. `remote-mcp-native-bundle.node.test.ts` additionally loads an actua
3831
3664
  minified production bundle to verify call/cache registration, request Context,
3832
3665
  native storage, saved-original delegates, custom replacements and closed-owner
3833
3666
  refusal. Existing wire, physical-attempt, cache and OAuth lifetime suites remain
3834
- the compatibility evidence; provider golden observations remain unchanged.
3667
+ the compatibility evidence.
3835
3668
 
3836
3669
  ### Native upward MCP orchestration (contributor)
3837
3670