@volter/twin-turbopuffer 0.1.37 → 1.0.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.
- package/README.md +12 -143
- package/dist/generated/pack-facts.json +43 -0
- package/dist/journeys/coverage.json +60 -0
- package/dist/journeys/customer-life.json +7 -0
- package/dist/journeys/customer-life.outline.md +13 -0
- package/dist/journeys/decisions.json +83 -0
- package/dist/journeys/demand.json +27 -0
- package/dist/journeys/score.json +82 -0
- package/dist/journeys/unreachable.json +12 -0
- package/dist/journeys/vendor-examples.json +7 -0
- package/dist/spec/SOURCE.md +56 -0
- package/dist/spec/doc-examples.json +11120 -0
- package/dist/spec/openapi.yaml.gz +0 -0
- package/dist/spec/patches.json +308 -0
- package/dist/spec/sources.json +78 -0
- package/dist/src/cli.js +8 -18
- package/dist/src/fetch.d.ts +2 -0
- package/dist/src/fetch.js +13 -0
- package/dist/src/generated/surface.gen.json +1 -1
- package/dist/src/index.d.ts +5 -11
- package/dist/src/index.js +10 -65
- package/dist/src/manifest.js +28 -23
- package/dist/src/semantics/index.d.ts +2 -0
- package/dist/src/semantics/index.js +1 -0
- package/dist/src/semantics/states.d.ts +1 -0
- package/dist/src/semantics/states.js +2 -0
- package/dist/src/server.d.ts +7 -0
- package/dist/src/server.js +7 -0
- package/generated/pack-facts.json +43 -0
- package/journeys/coverage.json +60 -0
- package/journeys/customer-life.json +7 -0
- package/journeys/customer-life.outline.md +13 -0
- package/journeys/decisions.json +83 -0
- package/journeys/demand.json +27 -0
- package/journeys/score.json +82 -0
- package/journeys/unreachable.json +12 -0
- package/journeys/vendor-examples.json +7 -0
- package/package.json +10 -21
- package/spec/SOURCE.md +56 -0
- package/spec/doc-examples.json +11120 -0
- package/spec/openapi.yaml.gz +0 -0
- package/spec/patches.json +308 -0
- package/spec/sources.json +78 -0
- package/src/cli.ts +8 -18
- package/src/fetch.ts +14 -0
- package/src/generated/surface.gen.json +1 -1
- package/src/index.ts +12 -92
- package/src/manifest.ts +29 -56
- package/src/semantics/index.ts +6 -0
- package/src/semantics/states.ts +2 -0
- package/src/server.ts +8 -0
- package/dist/src/key-gate.d.ts +0 -3
- package/dist/src/key-gate.js +0 -39
- package/dist/src/screens/dashboard.d.ts +0 -11
- package/dist/src/screens/dashboard.js +0 -191
- package/dist/src/semantics/namespaces.d.ts +0 -5
- package/dist/src/semantics/namespaces.js +0 -17
- package/dist/src/turbopuffer-capabilities.d.ts +0 -6
- package/dist/src/turbopuffer-capabilities.js +0 -442
- package/dist/src/turbopuffer-conformance.d.ts +0 -8
- package/dist/src/turbopuffer-conformance.js +0 -102
- package/dist/src/turbopuffer-connector.d.ts +0 -34
- package/dist/src/turbopuffer-connector.js +0 -152
- package/dist/src/turbopuffer-filter.d.ts +0 -57
- package/dist/src/turbopuffer-filter.js +0 -286
- package/dist/src/turbopuffer-server.d.ts +0 -23
- package/dist/src/turbopuffer-server.js +0 -72
- package/dist/src/turbopuffer-stem.d.ts +0 -1
- package/dist/src/turbopuffer-stem.js +0 -133
- package/dist/src/turbopuffer-store.d.ts +0 -80
- package/dist/src/turbopuffer-store.js +0 -1304
- package/dist/src/turbopuffer-text.d.ts +0 -44
- package/dist/src/turbopuffer-text.js +0 -189
- package/dist/src/turbopuffer-twin.d.ts +0 -25
- package/dist/src/turbopuffer-twin.js +0 -406
- package/src/key-gate.ts +0 -39
- package/src/screens/dashboard.tsx +0 -214
- package/src/semantics/namespaces.ts +0 -30
- package/src/turbopuffer-capabilities.ts +0 -455
- package/src/turbopuffer-conformance.ts +0 -101
- package/src/turbopuffer-connector.ts +0 -153
- package/src/turbopuffer-filter.ts +0 -277
- package/src/turbopuffer-server.ts +0 -81
- package/src/turbopuffer-stem.ts +0 -104
- package/src/turbopuffer-store.ts +0 -1157
- package/src/turbopuffer-text.ts +0 -204
- package/src/turbopuffer-twin.ts +0 -429
package/README.md
CHANGED
|
@@ -1,145 +1,14 @@
|
|
|
1
1
|
# @volter/twin-turbopuffer
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
```sh
|
|
17
|
-
world-turbopuffer serve --port 8787 --root ./state
|
|
18
|
-
TURBOPUFFER_API_KEY=anything TURBOPUFFER_BASE_URL='http://127.0.0.1:8787/{region}' node app.js
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
In a World, `volter-world init` wires this for you: the service exports `TURBOPUFFER_TWIN_URL` and
|
|
22
|
-
`TURBOPUFFER_BASE_URL=${url}/{region}`. The `{region}` placeholder is required: the SDK throws
|
|
23
|
-
"region is set, but would be ignored" when a caller passes `region` (Dub passes `aws-us-east-1`)
|
|
24
|
-
and the base URL has no placeholder. The twin accepts and ignores the leading region segment.
|
|
25
|
-
|
|
26
|
-
## Grounded wire
|
|
27
|
-
|
|
28
|
-
Grounded in the installed `@turbopuffer/turbopuffer@2.8.0` (`src/` paths below are that package's).
|
|
29
|
-
|
|
30
|
-
| Fact | Value | Source |
|
|
31
|
-
|---|---|---|
|
|
32
|
-
| Default host | `https://{region}.turbopuffer.com`, e.g. `aws-us-east-1.turbopuffer.com` | `src/client.ts:273` |
|
|
33
|
-
| Region | `region` option or `TURBOPUFFER_REGION`; required when the URL has `{region}` | `src/client.ts:255`, `274-286` |
|
|
34
|
-
| Base URL override | `TURBOPUFFER_BASE_URL` (or `baseURL`); `{region}` is substituted into it | `src/client.ts:253`, `281` |
|
|
35
|
-
| Auth | `Authorization: Bearer <apiKey>` (`TURBOPUFFER_API_KEY`) | `src/client.ts:254`, `383` |
|
|
36
|
-
| Request headers | `Accept: application/json`, `Accept-Encoding: identity`, `User-Agent`, `X-Stainless-*`, `Prefer: respond-async` | `src/client.ts:858-864`, `src/internal/custom/respond-async.ts` |
|
|
37
|
-
| Request body | JSON; gzip only with `compression: true` (default false) | `src/client.ts:299`, `812` |
|
|
38
|
-
| Node transport | undici `Agent.request`, selected by the `#fetch` import map for the `node` condition | `package.json` `imports`, `src/internal/custom/fetch-node.ts` |
|
|
39
|
-
| List namespaces | `GET /v1/namespaces?prefix&page_size&cursor` → `{ namespaces: [{id}], next_cursor }` | `src/client.ts:368`, `src/core/pagination.ts:123` |
|
|
40
|
-
| Write | `POST /v2/namespaces/{ns}` | `src/resources/namespaces.ts:174` |
|
|
41
|
-
| deleteAll | `DELETE /v2/namespaces/{ns}` → `{ status: 'OK' }` | `namespaces.ts:46`, `1100` |
|
|
42
|
-
| Query | `POST /v2/namespaces/{ns}/query` | `namespaces.ts:104` |
|
|
43
|
-
| multiQuery | `POST /v2/namespaces/{ns}/query?stainless_overload=multiQuery` with `{ queries }` | `namespaces.ts:90` |
|
|
44
|
-
| Metadata | `GET /v2/namespaces/{ns}/metadata` | `namespaces.ts:79` |
|
|
45
|
-
| Schema | `GET` / `POST /v1/namespaces/{ns}/schema` | `namespaces.ts:126`, `163` |
|
|
46
|
-
| Cache warm | `GET /v1/namespaces/{ns}/hint_cache_warm` | `namespaces.ts:68` |
|
|
47
|
-
| Write response | `{ status: 'OK', message, rows_affected, rows_upserted?, rows_patched?, rows_deleted?, *_ids?, billing }` | `namespaces.ts:1231-1294` |
|
|
48
|
-
| Query response | `{ rows?, aggregations?, billing, performance }`; a row is `{ id, $dist?, ...attributes }` | `namespaces.ts:850-868`, `1159-1175` |
|
|
49
|
-
| FTS defaults | tokenizer `word_v4`, `k1` 1.2, `b` 0.75, case-insensitive, stopwords kept (`remove_stopwords` false since January 2026), no stemming, `max_token_length` 39 | `namespaces.ts:474-526` |
|
|
50
|
-
| Filterable default | full-text attributes are not filterable unless `filterable: true` | `namespaces.ts:249-253` |
|
|
51
|
-
| Errors | status → `BadRequestError` 400, `AuthenticationError` 401, `NotFoundError` 404, … | `src/core/error.ts` |
|
|
52
|
-
|
|
53
|
-
Under Node the SDK sends through undici's `Agent.request`, which neither the injector's
|
|
54
|
-
http/https/fetch patches nor `HTTPS_PROXY` reach, so `TURBOPUFFER_BASE_URL` is the interception.
|
|
55
|
-
The descriptor also claims the regional hosts (`^(aws|gcp|azure)-….turbopuffer.com$`) for runtimes
|
|
56
|
-
that use the fetch build (Bun, edge).
|
|
57
|
-
|
|
58
|
-
## Coverage
|
|
59
|
-
|
|
60
|
-
Modelled (each has a `done` capability with a verify in `src/turbopuffer-capabilities.ts`):
|
|
61
|
-
|
|
62
|
-
- **write**: `upsert_rows`, `upsert_columns`, `patch_rows`, `patch_columns`, `deletes`,
|
|
63
|
-
`delete_by_filter`, `patch_by_filter`, `schema`, `distance_metric`, `return_affected_ids`,
|
|
64
|
-
`disable_backpressure` (accepted; the twin has no backpressure). One write request is one kernel
|
|
65
|
-
action. Extrapolated, not in the SDK: the twin applies it in the order filtered deletes →
|
|
66
|
-
filtered patches → upserts → patches → deletes.
|
|
67
|
-
Upserts replace the whole document; patches merge and never create; a `null` value removes the
|
|
68
|
-
attribute. Attribute types are declared or inferred on first write (`string`, `int`, `float`,
|
|
69
|
-
`bool`, `[]string`, …) and a mismatched value or type change is refused with 400.
|
|
70
|
-
- **query**: `filters` (Eq, NotEq, In, NotIn, Contains, NotContains, ContainsAny, NotContainsAny,
|
|
71
|
-
Lt/Lte/Gt/Gte, AnyLt/AnyLte/AnyGt/AnyGte, Glob/NotGlob/IGlob/NotIGlob, ContainsAllTokens,
|
|
72
|
-
ContainsAnyToken with `last_as_prefix`, And/Or/Not); `rank_by` BM25 (with `last_as_prefix`,
|
|
73
|
-
`Sum`, `Max`, `Product`), attribute order (`[attr, asc|desc]` and lists of them), and
|
|
74
|
-
`[vector, ANN|kNN, q]` with exact `cosine_distance` / `euclidean_squared`; `top_k` / `limit`
|
|
75
|
-
(default 10); `include_attributes` / `exclude_attributes`; `aggregate_by` Count, Count(attr),
|
|
76
|
-
Sum(attr); `consistency` (the twin is always strongly consistent); `multiQuery`.
|
|
77
|
-
- **namespaces**: list (prefix, cursor paging), metadata, schema read and update, cache-warm hint,
|
|
78
|
-
deleteAll. A query, metadata or schema read on a namespace that does not exist answers 404.
|
|
79
|
-
- **auth**: a missing or empty Bearer key is 401; `--token` makes the twin demand one exact key.
|
|
80
|
-
- **real state system**: `performTurbopufferAction` replays a recorded write / deleteAll / schema
|
|
81
|
-
update against the vendor; `syncTurbopufferFromRemote` observes namespaces, schema and documents
|
|
82
|
-
(paged by id) from a real account.
|
|
83
|
-
|
|
84
|
-
Semantics a caller depends on: an attribute a document does not carry reads as null, so `NotIn`,
|
|
85
|
-
`NotEq` and `NotContainsAny` match it (Dub omits `groupId`/`country` for exactly this). A
|
|
86
|
-
comparison filter on a non-filterable attribute is refused with 400; the token filters require
|
|
87
|
-
`full_text_search` on the attribute.
|
|
88
|
-
|
|
89
|
-
### Deterministic, not byte-equal
|
|
90
|
-
|
|
91
|
-
Scores and tokens are deterministic but are not Turbopuffer's exact numbers. `word_v2` is modelled
|
|
92
|
-
as maximal runs of Unicode letters, digits, marks and `_` (so a URL splits into its components, as
|
|
93
|
-
Dub measured); English stopwords are the 33-word Lucene list; BM25 is textbook Okapi with the
|
|
94
|
-
Lucene IDF `ln(1 + (N − n + 0.5)/(n + 0.5))` over the namespace's documents carrying the attribute;
|
|
95
|
-
a `last_as_prefix` final token contributes a constant 1 per matching document (Dub observed that a
|
|
96
|
-
single-token prefix query scores every match exactly 1). Ties order by id ascending. Error message
|
|
97
|
-
strings and the `{ status: 'error', error }` body are the twin's own reading (this build had no
|
|
98
|
-
account to probe); the SDK surfaces that body verbatim as `APIError.error`, and the statuses map to
|
|
99
|
-
the SDK's error classes. `billing` and `performance` are deterministic (logical bytes from the stored JSON,
|
|
100
|
-
zero timings, a "hot" cache).
|
|
101
|
-
|
|
102
|
-
Also the twin's own choices, not grounded in the SDK: namespace names `[A-Za-z0-9-_.]{1,128}`;
|
|
103
|
-
`page_size` at most 1000; `deletes` counts every requested id in `rows_deleted`; an undeclared
|
|
104
|
-
integer attribute is inferred as `int`; an attribute a row lacks projects as `null` when named in
|
|
105
|
-
`include_attributes`; a token filter whose every token is dropped (stopwords) matches nothing; id
|
|
106
|
-
comparisons order numbers before strings. A namespace refreshed from a real account whose
|
|
107
|
-
full-text config the twin does not model (the default `word_v4`, stemming, another language) is
|
|
108
|
-
stored, but BM25 and token filters on it are refused with a 400 naming the gap.
|
|
109
|
-
|
|
110
|
-
### Planned (todo)
|
|
111
|
-
|
|
112
|
-
Refused with a 400 or 404 naming the gap, never answered with a fabricated success: conditional
|
|
113
|
-
writes (`upsert_condition` / `patch_condition` / `delete_condition`), `copy_from_namespace`,
|
|
114
|
-
`branch_from_namespace`, `encryption`, `sharding`, `respond-async` polling (the twin answers
|
|
115
|
-
synchronously, which the SDK accepts), write backpressure, metadata PATCH (pinning), explain_query,
|
|
116
|
-
recall, `group_by`, `compute_attributes`, `aggregate_by` together with `rank_by`, `limit.per`,
|
|
117
|
-
`rerank_by`, rank expressions beyond BM25/Sum/Max/Product, highlights, Regex / Fuzzy /
|
|
118
|
-
ContainsTokenSequence filters, tokenizers other than `word_v2` and `pre_tokenized_array` (including
|
|
119
|
-
the default `word_v4`, so `full_text_search: true` is refused), stemming, non-English languages,
|
|
120
|
-
byte-equal BM25 scores, base64 vectors, named / multi / sparse vectors, server-side embedding, the
|
|
121
|
-
v1 namespace API older SDKs call, and the vendor's literal error strings.
|
|
122
|
-
|
|
123
|
-
The capability verifies were written but not run in the build that added this pack; the evidence
|
|
124
|
-
recorded there was the real `@turbopuffer/turbopuffer@2.8.0` client, constructed as Dub constructs
|
|
125
|
-
it, performing Dub's write → multiQuery → count → delete → deleteAll sequence against a served twin
|
|
126
|
-
through `TURBOPUFFER_BASE_URL`. The census `baseline` stays 0 until the catalog gate measures it.
|
|
127
|
-
|
|
128
|
-
### No UI mirror
|
|
129
|
-
|
|
130
|
-
Turbopuffer is used from code: an application writes and queries namespaces through the SDK. The
|
|
131
|
-
turbopuffer.com dashboard manages API keys, billing and namespace inspection; the work does not
|
|
132
|
-
happen there.
|
|
133
|
-
|
|
134
|
-
## Layout
|
|
135
|
-
|
|
136
|
-
| File | Role |
|
|
137
|
-
|---|---|
|
|
138
|
-
| `src/turbopuffer-twin.ts` | routing, auth, the error envelope, kernel reads and writes |
|
|
139
|
-
| `src/turbopuffer-store.ts` | namespaces and documents as tree subjects; pure write and query |
|
|
140
|
-
| `src/turbopuffer-filter.ts` | the filter language |
|
|
141
|
-
| `src/turbopuffer-text.ts` | tokenizer and BM25 |
|
|
142
|
-
| `src/turbopuffer-server.ts` | the fetch adapter and server |
|
|
143
|
-
| `src/turbopuffer-connector.ts` | perform and refresh adapters |
|
|
144
|
-
| `src/turbopuffer-capabilities.ts` | the capability manifest |
|
|
145
|
-
| `src/turbopuffer-conformance.ts` | endpoint probes and router census |
|
|
3
|
+
Protocol 3 twin of turbopuffer's API. Nothing is served: every spec operation
|
|
4
|
+
answers the vendor-shaped JSON gap (`404`, `{"status":"error","error":"not found"}`).
|
|
5
|
+
The [API overview](https://turbopuffer.com/docs/auth) documents this error envelope;
|
|
6
|
+
the pinned SDK maps 404 to `NotFoundError`. The vendor does not publish the exact
|
|
7
|
+
unknown-path message, so the pack uses `not found` in that envelope.
|
|
8
|
+
No vendor resource, namespace engine, screen, credential door or refresh is served.
|
|
9
|
+
|
|
10
|
+
Dub partner search requires an operator-supplied `TURBOPUFFER_API_KEY`; reads also
|
|
11
|
+
need `PARTNER_SEARCH_READ_ENABLED=true`. Both ship empty. The pinned settings are
|
|
12
|
+
recorded under `optional` in `journeys/demand.json`, and the life has no acts.
|
|
13
|
+
Published examples remain in `spec/doc-examples.json` and count as unserved.
|
|
14
|
+
`spec/SOURCE.md` preserves the vendor's document, its hash and path corrections.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"//": "GENERATED by scripts/pack-facts.ts — current pack descriptors and explicit world-runtime server backings; no prior-artifact entries are retained.",
|
|
3
|
+
"packs": {
|
|
4
|
+
"turbopuffer": {
|
|
5
|
+
"adoption": {
|
|
6
|
+
"sdks": [
|
|
7
|
+
"@turbopuffer/turbopuffer"
|
|
8
|
+
],
|
|
9
|
+
"pypi": [
|
|
10
|
+
"turbopuffer"
|
|
11
|
+
],
|
|
12
|
+
"scopes": [
|
|
13
|
+
"@turbopuffer/"
|
|
14
|
+
],
|
|
15
|
+
"envStems": [
|
|
16
|
+
"TURBOPUFFER"
|
|
17
|
+
]
|
|
18
|
+
},
|
|
19
|
+
"hosts": [
|
|
20
|
+
{
|
|
21
|
+
"hostPattern": "^(?:aws|gcp|azure)-[a-z0-9-]+\\.turbopuffer\\.com$"
|
|
22
|
+
}
|
|
23
|
+
],
|
|
24
|
+
"archetype": "crud",
|
|
25
|
+
"protocol": {
|
|
26
|
+
"declared": "3",
|
|
27
|
+
"major": 3,
|
|
28
|
+
"standing": "current"
|
|
29
|
+
},
|
|
30
|
+
"transport": "rest",
|
|
31
|
+
"resources": [],
|
|
32
|
+
"endpointEnv": {
|
|
33
|
+
"name": "TURBOPUFFER_TWIN_URL",
|
|
34
|
+
"templates": {
|
|
35
|
+
"TURBOPUFFER_BASE_URL": "${url}/{region}"
|
|
36
|
+
},
|
|
37
|
+
"note": "The pinned SDK requires the region placeholder when a region is supplied; its Node socket client reads TURBOPUFFER_BASE_URL."
|
|
38
|
+
},
|
|
39
|
+
"serveExport": "createTurbopufferTwinServer"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"undeclared": []
|
|
43
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"vendor": "turbopuffer",
|
|
3
|
+
"missing": 0,
|
|
4
|
+
"stale": [],
|
|
5
|
+
"code": {
|
|
6
|
+
"lines": 46,
|
|
7
|
+
"run": 44,
|
|
8
|
+
"recorded": 2,
|
|
9
|
+
"missing": 0
|
|
10
|
+
},
|
|
11
|
+
"state": {
|
|
12
|
+
"declared": 0,
|
|
13
|
+
"reached": 0,
|
|
14
|
+
"recorded": 0,
|
|
15
|
+
"missing": [],
|
|
16
|
+
"undeclared": []
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
{
|
|
20
|
+
"file": "semantics/index.ts",
|
|
21
|
+
"lines": {
|
|
22
|
+
"found": 2,
|
|
23
|
+
"hit": 2
|
|
24
|
+
},
|
|
25
|
+
"missing": []
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"file": "manifest.ts",
|
|
29
|
+
"lines": {
|
|
30
|
+
"found": 23,
|
|
31
|
+
"hit": 23
|
|
32
|
+
},
|
|
33
|
+
"missing": []
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"file": "index.ts",
|
|
37
|
+
"lines": {
|
|
38
|
+
"found": 7,
|
|
39
|
+
"hit": 7
|
|
40
|
+
},
|
|
41
|
+
"missing": []
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"file": "server.ts",
|
|
45
|
+
"lines": {
|
|
46
|
+
"found": 4,
|
|
47
|
+
"hit": 2
|
|
48
|
+
},
|
|
49
|
+
"missing": []
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"file": "fetch.ts",
|
|
53
|
+
"lines": {
|
|
54
|
+
"found": 10,
|
|
55
|
+
"hit": 10
|
|
56
|
+
},
|
|
57
|
+
"missing": []
|
|
58
|
+
}
|
|
59
|
+
]
|
|
60
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"vendor": "turbopuffer",
|
|
3
|
+
"host": "aws-us-east-1.turbopuffer.com",
|
|
4
|
+
"author": "Codex pack builder",
|
|
5
|
+
"about": "Demanded calls are recorded in demand.json and remain unserved in the retained gap. Scope is unchanged pending a separate implementation; supplying credentials is not opt-in.",
|
|
6
|
+
"steps": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# turbopuffer customer life
|
|
2
|
+
|
|
3
|
+
Author: Codex pack builder.
|
|
4
|
+
|
|
5
|
+
Demanded calls are recorded in demand.json and remain unserved in the retained gap. Scope is unchanged pending a separate implementation; supplying credentials is not opt-in.
|
|
6
|
+
|
|
7
|
+
Dub at `7e0101363b2ab30afc537c1893f159d1dcba513a` checks the key in
|
|
8
|
+
`apps/web/lib/api/partners/search/provider.ts:13` and the read flag at line 34.
|
|
9
|
+
The key authenticates demanded indexing; `PARTNER_SEARCH_READ_ENABLED` is the separate default-off read choice in `apps/web/.env.example:32`.
|
|
10
|
+
|
|
11
|
+
The retained gap has no modeled customer acts, credentials, screens or stored state; demand.json records the unserved demand.
|
|
12
|
+
Every spec operation answers the vendor-shaped gap. Published examples stay
|
|
13
|
+
in the spec and are counted as unserved; the life has no steps.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
{
|
|
2
|
+
"about": "Demanded calls are recorded in demand.json and remain unserved in the retained gap. Scope is unchanged pending a separate implementation; supplying credentials is not opt-in.",
|
|
3
|
+
"decisions": [
|
|
4
|
+
{
|
|
5
|
+
"operation": "get_v1_namespaces",
|
|
6
|
+
"demand": "None; Dub integration is opt-in.",
|
|
7
|
+
"mechanism": "unmodeled",
|
|
8
|
+
"why": "Demanded calls are recorded in demand.json and remain unserved in the retained gap. Scope is unchanged pending a separate implementation; supplying credentials is not opt-in."
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"operation": "post_v1_namespaces_namespace_debug_recall",
|
|
12
|
+
"demand": "None; Dub integration is opt-in.",
|
|
13
|
+
"mechanism": "unmodeled",
|
|
14
|
+
"why": "Demanded calls are recorded in demand.json and remain unserved in the retained gap. Scope is unchanged pending a separate implementation; supplying credentials is not opt-in."
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"operation": "get_v1_namespaces_namespace_hint_cache_warm",
|
|
18
|
+
"demand": "None; Dub integration is opt-in.",
|
|
19
|
+
"mechanism": "unmodeled",
|
|
20
|
+
"why": "Demanded calls are recorded in demand.json and remain unserved in the retained gap. Scope is unchanged pending a separate implementation; supplying credentials is not opt-in."
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"operation": "get_v1_namespaces_namespace_metadata",
|
|
24
|
+
"demand": "None; Dub integration is opt-in.",
|
|
25
|
+
"mechanism": "unmodeled",
|
|
26
|
+
"why": "Demanded calls are recorded in demand.json and remain unserved in the retained gap. Scope is unchanged pending a separate implementation; supplying credentials is not opt-in."
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"operation": "patch_v1_namespaces_namespace_metadata",
|
|
30
|
+
"demand": "None; Dub integration is opt-in.",
|
|
31
|
+
"mechanism": "unmodeled",
|
|
32
|
+
"why": "Demanded calls are recorded in demand.json and remain unserved in the retained gap. Scope is unchanged pending a separate implementation; supplying credentials is not opt-in."
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"operation": "get_v1_namespaces_namespace_operations_token",
|
|
36
|
+
"demand": "None; Dub integration is opt-in.",
|
|
37
|
+
"mechanism": "unmodeled",
|
|
38
|
+
"why": "Demanded calls are recorded in demand.json and remain unserved in the retained gap. Scope is unchanged pending a separate implementation; supplying credentials is not opt-in."
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"operation": "get_v1_namespaces_namespace_schema",
|
|
42
|
+
"demand": "None; Dub integration is opt-in.",
|
|
43
|
+
"mechanism": "unmodeled",
|
|
44
|
+
"why": "Demanded calls are recorded in demand.json and remain unserved in the retained gap. Scope is unchanged pending a separate implementation; supplying credentials is not opt-in."
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"operation": "post_v1_namespaces_namespace_schema",
|
|
48
|
+
"demand": "None; Dub integration is opt-in.",
|
|
49
|
+
"mechanism": "unmodeled",
|
|
50
|
+
"why": "Demanded calls are recorded in demand.json and remain unserved in the retained gap. Scope is unchanged pending a separate implementation; supplying credentials is not opt-in."
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"operation": "post_v2_namespaces_namespace",
|
|
54
|
+
"demand": "Shipped application call: apps/web/lib/api/partners/search/providers/turbopuffer.ts:405,416",
|
|
55
|
+
"mechanism": "unmodeled",
|
|
56
|
+
"why": "Demanded calls are recorded in demand.json and remain unserved in the retained gap. Scope is unchanged pending a separate implementation; supplying credentials is not opt-in."
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"operation": "delete_v2_namespaces_namespace",
|
|
60
|
+
"demand": "None; Dub integration is opt-in.",
|
|
61
|
+
"mechanism": "unmodeled",
|
|
62
|
+
"why": "Demanded calls are recorded in demand.json and remain unserved in the retained gap. Scope is unchanged pending a separate implementation; supplying credentials is not opt-in."
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"operation": "post_v2_namespaces_namespace_explain_query",
|
|
66
|
+
"demand": "None; Dub integration is opt-in.",
|
|
67
|
+
"mechanism": "unmodeled",
|
|
68
|
+
"why": "Demanded calls are recorded in demand.json and remain unserved in the retained gap. Scope is unchanged pending a separate implementation; supplying credentials is not opt-in."
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"operation": "get_v2_namespaces_namespace_metadata",
|
|
72
|
+
"demand": "None; Dub integration is opt-in.",
|
|
73
|
+
"mechanism": "unmodeled",
|
|
74
|
+
"why": "Demanded calls are recorded in demand.json and remain unserved in the retained gap. Scope is unchanged pending a separate implementation; supplying credentials is not opt-in."
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"operation": "post_v2_namespaces_namespace_query",
|
|
78
|
+
"demand": "None; Dub integration is opt-in.",
|
|
79
|
+
"mechanism": "unmodeled",
|
|
80
|
+
"why": "Demanded calls are recorded in demand.json and remain unserved in the retained gap. Scope is unchanged pending a separate implementation; supplying credentials is not opt-in."
|
|
81
|
+
}
|
|
82
|
+
]
|
|
83
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"measured": "Application calls and optional settings are recorded below at the cited commits.",
|
|
3
|
+
"applications": [
|
|
4
|
+
{
|
|
5
|
+
"name": "dubinc/dub",
|
|
6
|
+
"client": "partner search indexing and reads",
|
|
7
|
+
"backend": [
|
|
8
|
+
{
|
|
9
|
+
"call": "namespace.write: index upserts and deletes",
|
|
10
|
+
"operation": "post_v2_namespaces_namespace",
|
|
11
|
+
"evidence": "apps/web/lib/api/partners/search/providers/turbopuffer.ts:405,416"
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"commit": "7e0101363b2a",
|
|
15
|
+
"gate": "Shipped indexing/sync jobs use the write provider once its credential is supplied; PARTNER_SEARCH_READ_ENABLED controls only reads, not indexing (apps/web/lib/api/partners/search/provider.ts:9-19,22-38; apps/web/lib/api/partners/search/sync.ts:36,98).",
|
|
16
|
+
"evidence": "apps/web/lib/api/partners/search/provider.ts:13,34"
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"optional": [
|
|
20
|
+
{
|
|
21
|
+
"application": "dubinc/dub",
|
|
22
|
+
"what": "Index reads for partner search, separately from demanded indexing writes",
|
|
23
|
+
"setting": "Configuration (1): PARTNER_SEARCH_READ_ENABLED=true replaces false; read provider is separate from write provider (apps/web/lib/api/partners/search/provider.ts:22-38; apps/web/.env.example:32).",
|
|
24
|
+
"evidence": "apps/web/lib/api/partners/search/provider.ts:34"
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
{
|
|
2
|
+
"vendor": "turbopuffer",
|
|
3
|
+
"life": {
|
|
4
|
+
"steps": 0,
|
|
5
|
+
"verdict": "unjudged",
|
|
6
|
+
"judge": null,
|
|
7
|
+
"authors": []
|
|
8
|
+
},
|
|
9
|
+
"failures": [],
|
|
10
|
+
"flags": [],
|
|
11
|
+
"coverage": {
|
|
12
|
+
"vendor": "turbopuffer",
|
|
13
|
+
"missing": 0,
|
|
14
|
+
"stale": [],
|
|
15
|
+
"code": {
|
|
16
|
+
"lines": 46,
|
|
17
|
+
"run": 44,
|
|
18
|
+
"recorded": 2,
|
|
19
|
+
"missing": 0
|
|
20
|
+
},
|
|
21
|
+
"state": {
|
|
22
|
+
"declared": 0,
|
|
23
|
+
"reached": 0,
|
|
24
|
+
"recorded": 0,
|
|
25
|
+
"missing": [],
|
|
26
|
+
"undeclared": []
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
{
|
|
30
|
+
"file": "semantics/index.ts",
|
|
31
|
+
"lines": {
|
|
32
|
+
"found": 2,
|
|
33
|
+
"hit": 2
|
|
34
|
+
},
|
|
35
|
+
"missing": []
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"file": "manifest.ts",
|
|
39
|
+
"lines": {
|
|
40
|
+
"found": 23,
|
|
41
|
+
"hit": 23
|
|
42
|
+
},
|
|
43
|
+
"missing": []
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"file": "index.ts",
|
|
47
|
+
"lines": {
|
|
48
|
+
"found": 7,
|
|
49
|
+
"hit": 7
|
|
50
|
+
},
|
|
51
|
+
"missing": []
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"file": "server.ts",
|
|
55
|
+
"lines": {
|
|
56
|
+
"found": 4,
|
|
57
|
+
"hit": 2
|
|
58
|
+
},
|
|
59
|
+
"missing": []
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"file": "fetch.ts",
|
|
63
|
+
"lines": {
|
|
64
|
+
"found": 10,
|
|
65
|
+
"hit": 10
|
|
66
|
+
},
|
|
67
|
+
"missing": []
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
},
|
|
71
|
+
"examples": {
|
|
72
|
+
"done": false,
|
|
73
|
+
"replayed": true,
|
|
74
|
+
"verdict": "unjudged",
|
|
75
|
+
"failures": [],
|
|
76
|
+
"line": "examples: 99 published, 0 of patch-removed operations, 99 of operations the twin does not serve, 0 replayed, 0 recorded; 0 failing done: no"
|
|
77
|
+
},
|
|
78
|
+
"breadth": {
|
|
79
|
+
"operations": 13,
|
|
80
|
+
"gap": 13
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"code": [
|
|
3
|
+
{
|
|
4
|
+
"file": "server.ts",
|
|
5
|
+
"declarations": [
|
|
6
|
+
"createTurbopufferTwinServer"
|
|
7
|
+
],
|
|
8
|
+
"world": "host-process",
|
|
9
|
+
"why": "The journeys use the pack fetch in process; the server factory binds the external HTTP host, outside an in-process World walk."
|
|
10
|
+
}
|
|
11
|
+
]
|
|
12
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"vendor": "turbopuffer",
|
|
3
|
+
"host": "aws-us-east-1.turbopuffer.com",
|
|
4
|
+
"author": "Codex pack builder",
|
|
5
|
+
"about": "No demanded application calls turbopuffer; Dub partner search requires an operator-supplied TURBOPUFFER_API_KEY, and reads also require PARTNER_SEARCH_READ_ENABLED=true. Both ship empty. Published examples are retained and counted as unserved.",
|
|
6
|
+
"steps": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# turbopuffer spec — provenance
|
|
2
|
+
|
|
3
|
+
- **File:** `openapi.yaml.gz`, gzip of the OpenAPI document turbopuffer's official TypeScript client was generated
|
|
4
|
+
from, the vendor's bytes unchanged inside (OpenAPI 3.1.0, `info.version` `0.0.1`).
|
|
5
|
+
- **Upstream:** the client's `.stats.yml` at tag `v2.8.0`
|
|
6
|
+
(https://github.com/turbopuffer/turbopuffer-typescript/blob/v2.8.0/.stats.yml; 2.8.0 is the version dubinc/dub pins)
|
|
7
|
+
names `openapi_spec_url`
|
|
8
|
+
https://storage.googleapis.com/stainless-sdk-openapi-specs/turbopuffer-benesch/turbopuffer-e18ebc6e8f59aa35045717e326162e1e56ac3f344771f4149e17e1104f7b1c06.yml,
|
|
9
|
+
`openapi_spec_hash` `3db106e23d2536c8a73917ebb6047b19` (the MD5 of these bytes) and 14 configured endpoints. Fetched
|
|
10
|
+
2026-09-27.
|
|
11
|
+
- **Also published:** turbopuffer's API overview names a public specification, https://github.com/turbopuffer/turbopuffer-openapi
|
|
12
|
+
(https://turbopuffer.com/docs/auth, "Specification"). Its `openapi.yml` at commit `155e59adbecaa92b00a9c66edfad419cf0fe5c17`
|
|
13
|
+
(2026-08-04), whose `.stats.yml` names the same spec hash, parses to the same document as this file (it differs
|
|
14
|
+
only in YAML formatting). That repository's head has moved on (16 endpoints, adding the asynchronous copy's start and
|
|
15
|
+
poll); the file vendored here is the one the pinned client speaks.
|
|
16
|
+
- **SHA-256 of the uncompressed document:** `245e887f04ab7c111d8ab8b0812a631a0f04f4a7804f2f04c6601d90d090a27b`.
|
|
17
|
+
- **Operation ids:** the document names none, so each operation's id is the reader's `method_path` slug
|
|
18
|
+
(`post_v2_namespaces_namespace` is the write, `post_v2_namespaces_namespace_query` the query).
|
|
19
|
+
- **Corrections:** `patches.json` (RFC 6902, each with its reason and evidence), applied before the IR. The document
|
|
20
|
+
writes three pseudo-paths, `/v2/namespaces/{namespace}?stainless_overload=branchFrom`, `...?stainless_overload=copyFrom`
|
|
21
|
+
and `/v2/namespaces/{namespace}/query?stainless_overload=multiQuery`: its generator's way of giving one path and
|
|
22
|
+
method a second client method. The client sends that query key (`src/resources/namespaces.ts` at v2.8.0), but
|
|
23
|
+
turbopuffer's documentation names no such parameter: it branches and copies with `branch_from_namespace` and
|
|
24
|
+
`copy_from_namespace` in the body of `POST /v2/namespaces/:namespace` (https://turbopuffer.com/docs/write,
|
|
25
|
+
https://turbopuffer.com/docs/branching) and posts a multi-query's `queries` to the plain query path
|
|
26
|
+
(https://turbopuffer.com/docs/query). The patches fold each pseudo-path into that operation (the write body already
|
|
27
|
+
has both fields; the copy's `dest_encryption` moves into `CopyFromNamespaceConfig`; the query takes either body and
|
|
28
|
+
answers `QueryResult` or `MultiQueryResult`), leaving 13 operations. The derived routes retain the documented paths; all operations are unmodeled.
|
|
29
|
+
**Inference, not observation:** that turbopuffer's own server ignores `stainless_overload` is read from the
|
|
30
|
+
documentation, which never mentions it; no request to the real service was made.
|
|
31
|
+
- **Read by:** `bun scripts/derive-pack.ts turbopuffer`, which writes `../src/generated/`.
|
|
32
|
+
- **Pages cited:** the documentation's curl examples are rendered in the HTML pages' script payload, not their text;
|
|
33
|
+
the `.md` form of a page (https://turbopuffer.com/docs/query.md, listed in https://turbopuffer.com/llms.txt) is cited
|
|
34
|
+
where a quote comes from one.
|
|
35
|
+
- **The pages' examples** (`doc-examples.json`, 99): every example turbopuffer's documentation publishes for an
|
|
36
|
+
operation of this spec, from the API reference (Overview, Write, Query, Namespace metadata, Warm cache, List namespaces,
|
|
37
|
+
Delete namespace, Recall) and the guides (Quickstart, Full-Text Search, Branching, Embedding, Permissions, Ingestion,
|
|
38
|
+
Regions, Testing, Export, Backups, Pinning), read from each page's `.md` form (https://turbopuffer.com/llms.txt lists
|
|
39
|
+
them). An example is one request: a page's multi-language block shows one request in each client language, so it
|
|
40
|
+
counts once, by its curl form where it has one and otherwise by the request the page's client code sends (the
|
|
41
|
+
Embedding page's TypeScript, the Backups, Export, Testing, Pagination and custom-tokenization Python). The Chunking
|
|
42
|
+
page's example calls no turbopuffer operation, and the Quickstart's Connect block only sets shell variables; neither is
|
|
43
|
+
counted. The examples of Pinning (`PATCH /v1/namespaces/{namespace}/metadata`) and Recall are counted and not
|
|
44
|
+
replayed: the twin does not serve those operations.
|
|
45
|
+
- **Where the pages and this spec disagree:** the metadata page's example names `approx_size_bytes`,
|
|
46
|
+
`approx_num_rows` and `encryption.sse`, while its Response section and the spec name `approx_logical_bytes`,
|
|
47
|
+
`approx_row_count` and `encryption.mode`. The delete page shows `status: ok`, while the spec answers `OK`.
|
|
48
|
+
The spec defaults `remove_stopwords` to true and names `$embed_<attribute>`; the Write page defaults it to false
|
|
49
|
+
and names `embed_<attribute>`. No operation is served, so these examples remain unserved rather than replayed.
|
|
50
|
+
- **APIs the pages document and this spec omits, outside the count until modelled:** the asynchronous form of a copy
|
|
51
|
+
(`Prefer: respond-async`, answered 202 with a `Location` to poll, https://turbopuffer.com/docs/auth "Asynchronous
|
|
52
|
+
requests"), and the export read `GET /v1/namespaces/{namespace}` and `HEAD /v1/namespaces/{namespace}`, which the
|
|
53
|
+
document's own header says it leaves out (deprecated in favour of paging queries and the schema).
|
|
54
|
+
- **Outside any API:** API keys are made and expired on turbopuffer's dashboard ("You can create and expire tokens in
|
|
55
|
+
the dashboard", https://turbopuffer.com/docs/auth); its audit log names the two acts (`api-key-created`,
|
|
56
|
+
`api-key-marked-as-expired`, https://turbopuffer.com/docs/audit-logs).
|