@zackbart/connecta 0.16.0 → 0.16.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.
@@ -229,7 +229,13 @@ results explain that no single tool covered every term and recommend splitting
229
229
  distinct intents. A true negative says that no matching capability is
230
230
  configured and recommends refining, connector-scoping, or browsing; when a
231
231
  connector catalog was unavailable, the response includes
232
- `unavailableConnectorCount` instead of making that stronger claim. A search
232
+ `unavailableConnectorCount` instead of making that stronger claim. A no-match
233
+ query whose terms name a configured connector's `id` or `title` never makes it
234
+ either: connector identity is not in the lexical index — indexing it would move
235
+ ranking for every query that already matches tools — so instead the guidance on
236
+ an unscoped miss names up to three such connectors by ID and sends the caller
237
+ to a scoped browse. Identity affects that one sentence and nothing else: no
238
+ ranking, no result, and no new field. A search
233
239
  explicitly scoped to that unavailable connector also receives `catalogError` —
234
240
  the bounded classified failure (`code`, `message`, `retryable`, and any
235
241
  `retryAfterMs`) so the caller can tell a transient outage from one a deployment
@@ -166,7 +166,7 @@ should do next, and two of Notion's are easy to mistranslate.
166
166
  | 400 (`validation_error`, `invalid_json`, `invalid_request`, `missing_version`, …) | `invalid_args` | every documented 400 is a malformed request |
167
167
  | 401 `unauthorized` | `auth_required` | the token is missing or invalid |
168
168
  | 403 `restricted_resource` | `connector_call_failed`, non-retryable | **not** `auth_required` |
169
- | 404 `object_not_found` | `connector_call_failed`, non-retryable | overloaded; see below |
169
+ | 404 `object_not_found` | `connector_call_failed`, non-retryable | overloaded — deliberately **not** `not_found`; see below |
170
170
  | 409 `conflict_error` | `unavailable`, retryable | Notion says to retry |
171
171
  | 429 `rate_limited` | `rate_limited` + `retryAfterMs` | `Retry-After` seconds → ms |
172
172
  | 529 `service_overload` | `unavailable` + `retryAfterMs` | back off like a 429 |
@@ -184,7 +184,12 @@ whose message says an operator must change it in Notion.
184
184
  object that does not exist and for one that exists but has not been shared with
185
185
  the integration, and it will not say which. The message says both, because
186
186
  treating it as deletion is exactly how an agent concludes a page is gone when
187
- it was simply never shared.
187
+ it was simply never shared. This is why the row above does not use `not_found`,
188
+ which exists precisely to say "it is not there": the qualifier on that code
189
+ ([H11](./provider-conventions.md#h11--errors-are-mapped-to-what-the-caller-does-next))
190
+ is that the provider must tell absence apart from a permission gap, and Notion
191
+ does not. A program that skipped this id as missing would be right about half
192
+ the time, which is the half that matters.
188
193
 
189
194
  ## Rate limiting
190
195
 
@@ -18,6 +18,15 @@ rather than serving a smaller surface
18
18
  `new DynamicWorkerExecutor({ loader: env.LOADER })` from
19
19
  `@cloudflare/codemode`.
20
20
 
21
+ Both executor packages are optional peers: they never install with connecta,
22
+ and a deployment installs the one its runtime needs. The manifest publishes the
23
+ range each release supports — `^0.32.0` for `quickjs-emscripten`,
24
+ `^0.4.4 || ^0.5.0` for `@cloudflare/codemode` — so npm answers the version
25
+ question at install time rather than leaving a deployment to discover the skew
26
+ when a program runs ([#376](https://github.com/zackbart/connecta/issues/376)).
27
+ The version this repository tests against is one the published range admits,
28
+ and `test/package-surface.test.ts` fails if the two ever drift apart.
29
+
21
30
  There are exactly two deployment shapes.
22
31
  [`templates/node/`](../templates/node/) is what `connecta init` copies — the
23
32
  one standalone Node project, Docker-ready rather than Docker-only — and
@@ -108,9 +117,13 @@ deployment repository
108
117
  ```
109
118
 
110
119
  An upgrade is an intentional dependency change followed by a normal build.
111
- Instances must not share KV namespaces, D1 databases, secrets, or encryption
112
- keys. Keeping deployment configuration private is sensible even though this
113
- package is public.
120
+ Doing it to a deployment somebody else generated — reading its pin, diffing it
121
+ against the template generation it came from, and crossing the version
122
+ boundaries that break construction — is [upgrading](./upgrading.md), which is
123
+ written for the agent sitting inside that deployment rather than inside this
124
+ repository. Instances must not share KV namespaces, D1 databases, secrets, or
125
+ encryption keys. Keeping deployment configuration private is sensible even
126
+ though this package is public.
114
127
 
115
128
  ## Verification
116
129
 
@@ -118,7 +131,7 @@ package is public.
118
131
 
119
132
  | Script | What it gates |
120
133
  | --- | --- |
121
- | `check:docs` | local Markdown targets and fragments, guide and ethos size caps, duplicate heading anchors, a resurrected `docs/`, stale manual references |
134
+ | `check:docs` | local Markdown targets and fragments — including the `github.com` and `raw.githubusercontent.com` URLs that point back into this repository — guide and ethos size caps, duplicate heading anchors, a resurrected `docs/`, stale manual references |
122
135
  | `check:operator-ui` | the committed browser bundle matches its source, byte for byte |
123
136
  | `check:lint` | Oxlint's correctness category only — style is authored, not enforced |
124
137
  | `check:unused` | Knip's unused-export and dependency gate |
@@ -130,11 +143,38 @@ package is public.
130
143
  `npm run release:check` adds `check:security` (`npm audit --omit=dev
131
144
  --audit-level=moderate`) and `check:package`, and is what CI runs on every push
132
145
  and pull request. `check:package` packs the tarball, asserts the required files
133
- are in it and that no platform-specific implementation or unshippable path
134
- leaked in, derives the shipped guide list from which guides still carry a stub
135
- marker, checks that every packed doc's `documentation/` link resolves to
136
- something the tarball carries, and then runs `connecta init` and builds and
137
- runs the generated deployment's own container.
146
+ are in it and that no unshippable path leaked in — including any
147
+ Cloudflare-named connector or storage path (`connectors/cloudflare`,
148
+ `storage/cloudflare`) anywhere in the artifact, `dist/` and `examples/` alike
149
+ derives the shipped guide list from which guides still carry a stub marker,
150
+ hands the packed path list to `scripts/check-packed-links.mjs`, and then runs
151
+ `connecta init` and builds and runs the generated deployment's own container.
152
+
153
+ That last step enforces the packed-link policy, which is one sentence: **every
154
+ relative link in shipped Markdown must resolve to a path the tarball carries,
155
+ and a target that is repository-only is cited as an absolute
156
+ `https://github.com/zackbart/connecta/blob/main/...` URL** (the
157
+ `raw.githubusercontent.com` form for an image, which is how the README hero
158
+ still renders on npmjs.com). The tarball is built output, not a checkout: it
159
+ carries no `eval/`, `test/`, `scripts/`, or `assets/`, so a relative pointer
160
+ into any of them is a dead end for the reader who installed the package, and
161
+ the fix is never to ship those directories — that would undo the trim of
162
+ [#346](https://github.com/zackbart/connecta/issues/346). A repository URL keeps
163
+ the citation verifiable in both directions: an outside reader can follow it, and
164
+ `check:docs` resolves it back to the checkout and fails when the cited file
165
+ moves ([#378](https://github.com/zackbart/connecta/issues/378)). `CHANGELOG.md`
166
+ is exempt from both gates, because release notes quote the paths that existed
167
+ when they shipped.
168
+
169
+ The Worker example ships in the tarball, its Cloudflare KV and D1 adapters
170
+ included: it is the Workers starting template a consumer copies. That is not a
171
+ hole in the published surface, because nothing under `examples/` appears in the
172
+ `exports` map — every export target resolves into `dist/`, so those adapters
173
+ are reference source rather than an importable subpath. They also clear the
174
+ platform-specific gate above on their names (`cloudflare-kv.ts`,
175
+ `d1-activity.ts`) rather than by exemption: that gate is a blunt pattern over
176
+ the whole artifact, so an example file renamed into `storage/cloudflare` would
177
+ fail the pack even though nothing about the published surface had changed.
138
178
 
139
179
  Two more runners are deliberately outside `check`:
140
180
 
@@ -221,13 +261,14 @@ justification for *not* re-running it in workerd, so "it was easier" is not one.
221
261
  | Suite | Covers | Why Node |
222
262
  | --- | --- | --- |
223
263
  | `deployment-shapes.test.ts` | the Worker as the only example, one Node template that is also its own container, the same source running locally and in the container, the full operator surface in both, a template that cannot start on its own `.env.example`, a Worker README naming every optional peer its entrypoint imports, and the initializer's `.gitignore` staying in step | walks the template and example trees with Node filesystem APIs |
224
- | `doc-links.test.ts` | the documentation checker itself — local file and fragment resolution, duplicate heading slugs, fenced-code exclusion, and useful failures | spawns the Node checker against filesystem fixtures |
264
+ | `doc-links.test.ts` | the documentation checker itself — local file and fragment resolution, repository URLs resolved back to the checkout, duplicate heading slugs, fenced-code exclusion, and useful failures | spawns the Node checker against filesystem fixtures |
225
265
  | `doctor-cli.test.ts` | `connecta doctor`'s executor line end to end — the sandbox the deployment reports is the one named, an unidentifiable executor gets an executor-neutral line, and a hostile name is bounded and stripped before it reaches a terminal | spawns the CLI against a Node HTTP deployment over real sockets |
226
266
  | `drift-check.test.ts` | the maintainer drift checker — recorded touched endpoints, a quiet revision bump, clear failures for an unavailable spec/manifest/credential, `$ref` traversal, and one well-formed row per endpoint | spawns the Node checker against filesystem fixtures |
227
267
  | `file-storage.test.ts` | `fileStorage()` across instances, logical TTL plus physical pruning without clobbering a newer value, and corrupt-file quarantine | exercises the Node filesystem storage adapter |
228
268
  | `guest-api-contract-quickjs.test.ts` | the shared guest-contract cases on the real QuickJS executor | runs the contract cases on the Node QuickJS executor |
229
269
  | `node.test.ts` | the `listen()` adapter propagating an HTTP client disconnect through the Web `Request` and the MCP handler into a program's connector call, releasing both admission permits | exercises the Node HTTP adapter over real TCP sockets |
230
- | `package-surface.test.ts` | the published boundarybuilt output shipped, only generic factories, platform storage kept in examples, Clerk and QuickJS behind optional subpaths, every provider independently importable, and the Cloudflare provider free of bare specifiers | walks the package tree with Node filesystem APIs |
270
+ | `packed-links.test.ts` | the packed-link gate itself shipped targets and repository URLs accepted, relative links into unshipped paths and directories rejected with the citation to write instead, reference definitions seen, fenced examples ignored, the changelog exempt | spawns the Node packed-link gate against filesystem fixtures |
271
+ | `package-surface.test.ts` | the published boundary — built output shipped, the `exports` map carrying exactly the documented subpaths plus `./package.json`, only generic factories, platform storage kept in examples, Clerk and QuickJS behind optional subpaths, every provider independently importable, and the Cloudflare provider free of bare specifiers | walks the package tree with Node filesystem APIs |
231
272
  | `purity.test.ts` | the import-graph guardrail ([architecture](./architecture.md#import-graph-purity)) — the core stays Workers-clean | walks the source import graph with Node filesystem APIs |
232
273
  | `quickjs-child-entry.test.ts` | a missing QuickJS child entry failing before `fork()`, with the expected path and the bundler-externalization constraint | mocks Node child-process and filesystem APIs |
233
274
  | `quickjs-child-stderr.test.ts` | abnormal child exits retaining only an 8 KiB stderr tail, included in the parent-side diagnostic | mocks Node child-process streams |
@@ -235,6 +276,7 @@ justification for *not* re-running it in workerd, so "it was easier" is not one.
235
276
  | `quickjs-log-limits.test.ts` | bounded `console.*` capture — per-entry cut, cumulative character and transport budgets, escape-heavy floods preserving the guest result | runs the Node QuickJS child-process executor |
236
277
  | `suite-partition.test.ts` | this partition, including itself: every `*.test.ts` in exactly one list, stale entries and empty reasons refused | walks the test directory to guard the partition |
237
278
  | `template-file-activity.test.ts` | the Node template's own activity store — persistence across restart, torn-line repair, newest-first paging, and compaction past the slack window | runs it against real files |
279
+ | `upgrade-guide.test.ts` | the [upgrade guide](./upgrading.md)'s claims about somebody else's deployment — the generated file inventory, the seven tool names doctor demands, version boundaries that actually shipped, a bump target that is this release, and the three places a reader finds it | reads the guide, the template tree, and the CLI with Node filesystem APIs |
238
280
  | `version.test.ts` | `CONNECTA_VERSION` matching `package.json` | reads `package.json` with Node filesystem APIs |
239
281
 
240
282
  ### Outside `npm run check`
@@ -14,7 +14,7 @@ error, not a finding, so the proxy reports have no H rows.
14
14
  Every miss below is fixed in the same change that recorded it
15
15
  ([#342](https://github.com/zackbart/connecta/issues/342)), except where the row
16
16
  says otherwise. The mechanically checkable half of the hand-written bar is now
17
- a test — [`test/provider-conventions.test.ts`](../test/provider-conventions.test.ts)
17
+ a test — [`test/provider-conventions.test.ts`](https://github.com/zackbart/connecta/blob/main/test/provider-conventions.test.ts)
18
18
  walks the shipped surface of both `api()` providers on every run, so these
19
19
  verdicts cannot rot quietly back into prose. The proxies' mechanical rows live
20
20
  in their own suites, because what they assert is the wrapper's identity,
@@ -64,7 +64,9 @@ floor. From `src/catalog.ts` and `src/catalog-service.ts`:
64
64
  fallback summary for a guide with no usable body line. Routing facts belong
65
65
  in the title and the guide's first line; a routing fact that lives only in
66
66
  the connector description has been written into a field the model does not
67
- read.
67
+ read. Neither the `id` nor the `title` is a lexical document, so a term drawn
68
+ from one of them is not a search hit — it is a no-match whose guidance names
69
+ the connector and points at a scoped browse.
68
70
 
69
71
  Two construction-time checks enforce the floor beneath all of this. The hard
70
72
  one is `api()` itself: since
@@ -108,7 +110,10 @@ write never hides behind a neutral one. Escape hatches are named
108
110
  `<provider>_api_<class>` so they sort together and read as generic.
109
111
 
110
112
  *Why:* the name is the only thing lexical search indexes besides the
111
- description, and it is what an agent skims first. *Cost:* wrong-tool selection.
113
+ description, and it is what an agent skims first. A connector's `id` and
114
+ `title` are displayed, not indexed — a search for one of them matches no tool,
115
+ and the miss is answered by guidance naming that connector rather than by a
116
+ ranked result. *Cost:* wrong-tool selection.
112
117
 
113
118
  ### H3 — The selection sentence fits in 160 characters; the whole description in 240
114
119
 
@@ -217,6 +222,37 @@ convenient reading. A call that can only fail is refused locally as
217
222
  `invalid_args` before the round trip. Provider error prose is never parsed to
218
223
  invent a classification.
219
224
 
225
+ **A downstream 404 is `not_found` — when the provider means it.** The code
226
+ exists because the next move is none of the others': you do not wait, you do
227
+ not send the agent to `authorize_connector`, you do not repair the argument
228
+ object. You re-address — look the id up again, or accept the absence and carry
229
+ on — and a program looping over ids inside `execute_code` can continue past
230
+ `not_found` where `connector_call_failed` would have to abort the run, reading
231
+ the code off a `connecta.batch` entry's `errorDetails` rather than off a caught
232
+ error, which the guest bridge has already stripped to prose. That
233
+ control-flow difference is the H11 test being met; it is not a label for the
234
+ cause.
235
+
236
+ The qualifier is the whole rule. Map a status to `not_found` only where the
237
+ provider distinguishes absence from a permission gap. Where it does not —
238
+ Notion returns `object_not_found` both for an object that is gone and for one
239
+ that was never shared with the integration, and will not say which — the honest
240
+ code stays `connector_call_failed` (or `auth_required`, where a credential
241
+ really is the fix) and the message states the ambiguity, exactly as the
242
+ paragraph above requires. Cloudflare is the other side of the pair: a token
243
+ that may not touch a resource is refused with 401 or 403, so its 404 is an
244
+ absence and maps to `not_found`. Neither connector's mapping changed shape when
245
+ the code arrived; one of them changed codes.
246
+
247
+ Two boundaries. `not_found` is about a resource the *downstream* owns: an
248
+ address connecta cannot resolve is already framed as `unknown_address` or
249
+ `unknown_tool` and never reaches a connector. And it never appears on the
250
+ hosted-MCP proxy path, because `P1` forbids re-shaping downstream framing and
251
+ prose is never parsed to invent a classification — a proxied server's own
252
+ missing-resource error arrives as that server wrote it. The two paths do not
253
+ diverge on the rule; they diverge on who is entitled to apply it, which is the
254
+ same split every other code already has.
255
+
220
256
  *Why:* a misrouted error sends an agent down a recovery path that cannot
221
257
  succeed. *Cost:* argument retries.
222
258
 
@@ -508,7 +544,7 @@ whether or not anybody noticed it arrived.
508
544
  ([#351](https://github.com/zackbart/connecta/issues/351)): a human at a laptop,
509
545
  before a release, with local credentials and the published specifications in
510
546
  front of them. It lives in
511
- [`scripts/drift-check.mjs`](../scripts/drift-check.mjs) and ships nowhere —
547
+ [`scripts/drift-check.mjs`](https://github.com/zackbart/connecta/blob/main/scripts/drift-check.mjs) and ships nowhere —
512
548
  `scripts/` is outside the package, no runtime module imports it, and nothing it
513
549
  reads becomes a runtime input.
514
550
 
@@ -528,7 +564,7 @@ message naming it rather than reporting an empty catalog as mass removal.
528
564
 
529
565
  **Touched endpoints.** A hand-written provider is written against a published
530
566
  OpenAPI document and calls a few dozen of its operations, so
531
- [`scripts/drift/`](../scripts/drift/) commits exactly those: method, path, the
567
+ [`scripts/drift/`](https://github.com/zackbart/connecta/tree/main/scripts/drift) commits exactly those: method, path, the
532
568
  specification revision a release reviewed the endpoint at, whether the
533
569
  operation was deprecated at that revision, and a digest of that endpoint's
534
570
  contract. `--specs` fetches each provider's published document and reports four
@@ -580,7 +616,7 @@ the reason). A convention is never quietly skipped, and an accepted miss is
580
616
  recorded as a provider-specific exception with its argument, not left blank.
581
617
  Its five reports live in [provider-audit.md](./provider-audit.md), and the
582
618
  mechanically checkable half of the hand-written bar runs on every test run in
583
- [`test/provider-conventions.test.ts`](../test/provider-conventions.test.ts) —
619
+ [`test/provider-conventions.test.ts`](https://github.com/zackbart/connecta/blob/main/test/provider-conventions.test.ts) —
584
620
  so a convention that was met once stays met, or fails loudly.
585
621
 
586
622
  Hand-written providers are audited against H1–H14; hosted-MCP proxies against
@@ -620,7 +656,7 @@ beats the escape hatch — is a reading, and the audit reports it as one. The
620
656
  Cloudflare keep/prune half of that judgment was made in
621
657
  [#350](https://github.com/zackbart/connecta/issues/350): 30 keep, 18 improve,
622
658
  3 prune, measured per tool in
623
- [`eval/current-version/results/issue-350-evidence.md`](../eval/current-version/results/issue-350-evidence.md).
659
+ [`eval/current-version/results/issue-350-evidence.md`](https://github.com/zackbart/connecta/blob/main/eval/current-version/results/issue-350-evidence.md).
624
660
  Its eighteen `improve` rows are H8 and H9 misses on tools that clearly earn
625
661
  their place, so they are this audit's work, not a second removal argument.
626
662