@volter/twin-turbopuffer 1.0.0 → 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.
Files changed (64) hide show
  1. package/README.md +12 -139
  2. package/dist/generated/pack-facts.json +2 -16
  3. package/dist/journeys/coverage.json +60 -0
  4. package/dist/journeys/customer-life.json +7 -0
  5. package/dist/journeys/customer-life.outline.md +13 -0
  6. package/dist/journeys/decisions.json +83 -0
  7. package/dist/journeys/demand.json +27 -0
  8. package/dist/journeys/score.json +82 -0
  9. package/dist/journeys/unreachable.json +12 -0
  10. package/dist/journeys/vendor-examples.json +7 -0
  11. package/dist/spec/SOURCE.md +6 -9
  12. package/dist/spec/sources.json +25 -0
  13. package/dist/src/fetch.js +0 -6
  14. package/dist/src/generated/ui.gen.json +1 -1
  15. package/dist/src/index.js +5 -3
  16. package/dist/src/manifest.js +27 -88
  17. package/dist/src/semantics/index.js +1 -6
  18. package/dist/src/semantics/states.d.ts +1 -0
  19. package/dist/src/semantics/states.js +2 -0
  20. package/generated/pack-facts.json +2 -16
  21. package/journeys/coverage.json +60 -0
  22. package/journeys/customer-life.json +7 -0
  23. package/journeys/customer-life.outline.md +13 -0
  24. package/journeys/decisions.json +83 -0
  25. package/journeys/demand.json +27 -0
  26. package/journeys/score.json +82 -0
  27. package/journeys/unreachable.json +12 -0
  28. package/journeys/vendor-examples.json +7 -0
  29. package/package.json +4 -8
  30. package/spec/SOURCE.md +6 -9
  31. package/spec/sources.json +25 -0
  32. package/src/fetch.ts +0 -6
  33. package/src/generated/ui.gen.json +1 -1
  34. package/src/index.ts +6 -4
  35. package/src/manifest.ts +28 -122
  36. package/src/semantics/index.ts +0 -4
  37. package/src/semantics/states.ts +2 -0
  38. package/dist/src/engine/filter.d.ts +0 -57
  39. package/dist/src/engine/filter.js +0 -286
  40. package/dist/src/engine/namespace.d.ts +0 -67
  41. package/dist/src/engine/namespace.js +0 -1248
  42. package/dist/src/engine/stem.d.ts +0 -1
  43. package/dist/src/engine/stem.js +0 -133
  44. package/dist/src/engine/text.d.ts +0 -44
  45. package/dist/src/engine/text.js +0 -189
  46. package/dist/src/screens/dashboard.d.ts +0 -4
  47. package/dist/src/screens/dashboard.js +0 -145
  48. package/dist/src/semantics/around.d.ts +0 -2
  49. package/dist/src/semantics/around.js +0 -30
  50. package/dist/src/semantics/doors.d.ts +0 -9
  51. package/dist/src/semantics/doors.js +0 -31
  52. package/dist/src/semantics/namespaces.d.ts +0 -8
  53. package/dist/src/semantics/namespaces.js +0 -98
  54. package/dist/src/semantics/shared.d.ts +0 -24
  55. package/dist/src/semantics/shared.js +0 -57
  56. package/src/engine/filter.ts +0 -277
  57. package/src/engine/namespace.ts +0 -1107
  58. package/src/engine/stem.ts +0 -104
  59. package/src/engine/text.ts +0 -204
  60. package/src/screens/dashboard.tsx +0 -169
  61. package/src/semantics/around.ts +0 -28
  62. package/src/semantics/doors.ts +0 -33
  63. package/src/semantics/namespaces.ts +0 -105
  64. package/src/semantics/shared.ts +0 -63
package/README.md CHANGED
@@ -1,141 +1,14 @@
1
1
  # @volter/twin-turbopuffer
2
2
 
3
- A local, stateful twin of the [Turbopuffer](https://turbopuffer.com) API (v2 namespaces), built on
4
- `@volter/world-core`. The unmodified `@turbopuffer/turbopuffer` client writes documents into it and
5
- queries them back: filters, BM25 full-text ranking, attribute ordering, exact vector distance and
6
- counts are computed from the stored documents, deterministically.
7
-
8
- The motivating consumer is Dub's partner search (`apps/web/lib/api/partners/search/providers/
9
- turbopuffer.ts`): its sync jobs `write` `upsert_rows` with a declared schema and `deletes`, its
10
- search runs a `multiQuery` of BM25 branches with `last_as_prefix`, `ContainsAllTokens` and program /
11
- group / tag filters, its count runs `aggregate_by: { total: ['Count'] }`, and its maintenance script
12
- calls `deleteAll`.
13
-
14
- ## Pointing a client at it
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-*` | `src/client.ts:858-864` |
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
- | Write | `POST /v2/namespaces/{ns}` | `src/resources/namespaces.ts:174` |
40
- | deleteAll | `DELETE /v2/namespaces/{ns}` → `{ status: 'OK' }` | `namespaces.ts:46`, `1100` |
41
- | Query | `POST /v2/namespaces/{ns}/query` | `namespaces.ts:104` |
42
- | multiQuery | `POST /v2/namespaces/{ns}/query?stainless_overload=multiQuery` with `{ queries }` | `namespaces.ts:90` |
43
- | Write response | `{ status: 'OK', message, rows_affected, rows_upserted?, rows_patched?, rows_deleted?, *_ids?, billing }` | `namespaces.ts:1231-1294` |
44
- | Query response | `{ rows?, aggregations?, billing, performance }`; a row is `{ id, $dist?, ...attributes }` | `namespaces.ts:850-868`, `1159-1175` |
45
- | 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` |
46
- | Filterable default | full-text attributes are not filterable unless `filterable: true` | `namespaces.ts:249-253` |
47
- | Errors | status → `BadRequestError` 400, `AuthenticationError` 401, `NotFoundError` 404, … | `src/core/error.ts` |
48
-
49
- Under Node the SDK sends through undici's `Agent.request`, which neither the injector's
50
- http/https/fetch patches nor `HTTPS_PROXY` reach, so `TURBOPUFFER_BASE_URL` is the interception.
51
- The descriptor also claims the regional hosts (`^(aws|gcp|azure)-….turbopuffer.com$`) for runtimes
52
- that use the fetch build (Bun, edge).
53
-
54
- ## Coverage
55
-
56
- Modelled:
57
-
58
- - **write**: `upsert_rows`, `upsert_columns`, `patch_rows`, `patch_columns`, `deletes`,
59
- `delete_by_filter`, `patch_by_filter`, `schema`, `distance_metric`, `return_affected_ids`,
60
- `disable_backpressure` (accepted; the twin has no backpressure). One write request is one kernel
61
- action. Extrapolated, not in the SDK: the twin applies it in the order filtered deletes →
62
- filtered patches → upserts → patches → deletes.
63
- Upserts replace the whole document; patches merge and never create; a `null` value removes the
64
- attribute. Attribute types are declared or inferred on first write (`string`, `int`, `float`,
65
- `bool`, `[]string`, …) and a mismatched value or type change is refused with 400.
66
- - **query**: `filters` (Eq, NotEq, In, NotIn, Contains, NotContains, ContainsAny, NotContainsAny,
67
- Lt/Lte/Gt/Gte, AnyLt/AnyLte/AnyGt/AnyGte, Glob/NotGlob/IGlob/NotIGlob, ContainsAllTokens,
68
- ContainsAnyToken with `last_as_prefix`, And/Or/Not); `rank_by` BM25 (with `last_as_prefix`,
69
- `Sum`, `Max`, `Product`), attribute order (`[attr, asc|desc]` and lists of them), and
70
- `[vector, ANN|kNN, q]` with exact `cosine_distance` / `euclidean_squared`; `top_k` / `limit`
71
- (default 10); `include_attributes` / `exclude_attributes`; `aggregate_by` Count, Count(attr),
72
- Sum(attr); `consistency` (the twin is always strongly consistent); `multiQuery`.
73
- - **namespaces**: deleteAll. A query on a namespace that does not exist answers 404. Listing, metadata, the schema
74
- endpoints and the cache-warm hint are called by no application here ([journeys/demand.json](./journeys/demand.json))
75
- and answer the gap.
76
- - **auth**: a missing or empty Bearer key is 401; a key the dashboard (or the World's credential door, which issues the
77
- application's `TURBOPUFFER_API_KEY`) never made, or one it expired, is 401.
78
- - **no state system** (the gap): a World's writes are not performed against turbopuffer, and a real account's
79
- namespaces are not observed.
80
-
81
- Semantics a caller depends on: an attribute a document does not carry reads as null, so `NotIn`,
82
- `NotEq` and `NotContainsAny` match it (Dub omits `groupId`/`country` for exactly this). A
83
- comparison filter on a non-filterable attribute is refused with 400; the token filters require
84
- `full_text_search` on the attribute.
85
-
86
- ### Deterministic, not byte-equal
87
-
88
- Scores and tokens are deterministic but are not Turbopuffer's exact numbers. `word_v2` is modelled
89
- as maximal runs of Unicode letters, digits, marks and `_` (so a URL splits into its components, as
90
- Dub measured); English stopwords are the 33-word Lucene list; BM25 is textbook Okapi with the
91
- Lucene IDF `ln(1 + (N − n + 0.5)/(n + 0.5))` over the namespace's documents carrying the attribute;
92
- a `last_as_prefix` final token contributes a constant 1 per matching document (Dub observed that a
93
- single-token prefix query scores every match exactly 1). Ties order by id ascending. Error message
94
- strings and the `{ status: 'error', error }` body are the twin's own reading (this build had no
95
- account to probe); the SDK surfaces that body verbatim as `APIError.error`, and the statuses map to
96
- the SDK's error classes. `billing` and `performance` are deterministic (logical bytes from the stored JSON,
97
- zero timings, a "hot" cache).
98
-
99
- Also the twin's own choices, not grounded in the SDK: namespace names `[A-Za-z0-9-_.]{1,128}`;
100
- `page_size` at most 1000; `deletes` counts every requested id in `rows_deleted`; an undeclared
101
- integer attribute is inferred as `int`; an attribute a row lacks projects as `null` when named in
102
- `include_attributes`; a token filter whose every token is dropped (stopwords) matches nothing; id
103
- comparisons order numbers before strings.
104
-
105
- ### Planned (todo)
106
-
107
- Refused with a 400 or 404 naming the gap, never answered with a fabricated success: conditional
108
- writes (`upsert_condition` / `patch_condition` / `delete_condition`), `copy_from_namespace`,
109
- `branch_from_namespace` and their asynchronous operations, `encryption`, `sharding`, write backpressure, metadata PATCH (pinning), explain_query,
110
- recall, `group_by`, `compute_attributes`, `aggregate_by` together with `rank_by`, `limit.per`,
111
- `rerank_by`, rank expressions beyond BM25/Sum/Max/Product, highlights, Regex / Fuzzy /
112
- ContainsTokenSequence filters, tokenizers other than `word_v2` and `pre_tokenized_array` (including
113
- the default `word_v4`, so `full_text_search: true` is refused), stemming, non-English languages,
114
- byte-equal BM25 scores, base64 vectors, named / multi / sparse vectors, server-side embedding, the
115
- v1 namespace API older SDKs call, and the vendor's literal error strings.
116
-
117
- The evidence recorded when the pack was built was the real `@turbopuffer/turbopuffer@2.8.0` client, constructed as
118
- Dub constructs it, performing Dub's write → multiQuery → count → delete → deleteAll sequence against a served twin
119
- through `TURBOPUFFER_BASE_URL`.
120
-
121
- ### No UI mirror
122
-
123
- Turbopuffer is used from code: an application writes and queries namespaces through the SDK. The
124
- turbopuffer.com dashboard manages API keys, billing and namespace inspection; the work does not
125
- happen there.
126
-
127
- ## Layout
128
-
129
- | File | Role |
130
- |---|---|
131
- | `src/fetch.ts` | the region segment, the API key gate, the derived dispatch |
132
- | `src/server.ts` | the discovery door, the dashboard, the server |
133
- | `src/semantics/namespaces.ts` | the handlers, one per operation |
134
- | `src/semantics/shared.ts` | the namespaces from the tree, the error body, a write landed |
135
- | `src/engine/namespace.ts` | namespaces and documents; the pure write and query |
136
- | `src/engine/filter.ts` | the filter language |
137
- | `src/engine/text.ts`, `src/engine/stem.ts` | tokenizer, English stemming and BM25 |
138
- | `src/screens/api-keys.tsx` | the dashboard's sign-in and API keys |
139
-
140
- A World's writes are not performed against turbopuffer and its namespaces are not observed from it (no state system:
141
- the gap).
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.
@@ -19,10 +19,6 @@
19
19
  "hosts": [
20
20
  {
21
21
  "hostPattern": "^(?:aws|gcp|azure)-[a-z0-9-]+\\.turbopuffer\\.com$"
22
- },
23
- {
24
- "host": "turbopuffer.com",
25
- "pathPattern": "^/(login|dashboard|_twin/users)(/|$)"
26
22
  }
27
23
  ],
28
24
  "archetype": "crud",
@@ -32,23 +28,13 @@
32
28
  "standing": "current"
33
29
  },
34
30
  "transport": "rest",
35
- "resources": [
36
- "namespace",
37
- "document"
38
- ],
31
+ "resources": [],
39
32
  "endpointEnv": {
40
33
  "name": "TURBOPUFFER_TWIN_URL",
41
34
  "templates": {
42
35
  "TURBOPUFFER_BASE_URL": "${url}/{region}"
43
36
  },
44
- "note": "grounded in @turbopuffer/turbopuffer@2.8.0 src/client.ts:253-288 (TURBOPUFFER_BASE_URL, {region} placeholder substitution) and internal/custom/fetch-node.ts (undici Agent.request under node, outside the injector); the injector also claims the regional *.turbopuffer.com hosts for fetch-based runtimes."
45
- },
46
- "credentialDoor": {
47
- "path": "/_twin/app-credentials",
48
- "body": {},
49
- "fill": {
50
- "TURBOPUFFER_API_KEY": "api_key"
51
- }
37
+ "note": "The pinned SDK requires the region placeholder when a region is supplied; its Node socket client reads TURBOPUFFER_BASE_URL."
52
38
  },
53
39
  "serveExport": "createTurbopufferTwinServer"
54
40
  }
@@ -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
+ }
@@ -25,7 +25,7 @@
25
25
  https://turbopuffer.com/docs/branching) and posts a multi-query's `queries` to the plain query path
26
26
  (https://turbopuffer.com/docs/query). The patches fold each pseudo-path into that operation (the write body already
27
27
  has both fields; the copy's `dest_encryption` moves into `CopyFromNamespaceConfig`; the query takes either body and
28
- answers `QueryResult` or `MultiQueryResult`), leaving 11 operations. The twin routes by path and ignores the key.
28
+ answers `QueryResult` or `MultiQueryResult`), leaving 13 operations. The derived routes retain the documented paths; all operations are unmodeled.
29
29
  **Inference, not observation:** that turbopuffer's own server ignores `stainless_overload` is read from the
30
30
  documentation, which never mentions it; no request to the real service was made.
31
31
  - **Read by:** `bun scripts/derive-pack.ts turbopuffer`, which writes `../src/generated/`.
@@ -42,14 +42,11 @@
42
42
  page's example calls no turbopuffer operation, and the Quickstart's Connect block only sets shell variables; neither is
43
43
  counted. The examples of Pinning (`PATCH /v1/namespaces/{namespace}/metadata`) and Recall are counted and not
44
44
  replayed: the twin does not serve those operations.
45
- - **Where the pages and this spec disagree** (each an `exampleDiffers` in `../journeys/vendor-examples.json`): the
46
- metadata page's example answer names `approx_size_bytes`, `approx_num_rows` and `encryption: {"sse": true}`, where the
47
- same page's Response section and this spec's `NamespaceMetadata` name `approx_logical_bytes`, `approx_row_count` and
48
- `encryption.mode`; the delete page's example answers `"status": "ok"`, where this spec's delete answer is the constant
49
- `"OK"`. The twin answers the spec. `remove_stopwords` defaults to `true` in this spec's description and to `false` on
50
- the Write page ("Defaults to false (i.e. keep common words)") and in the January 2026 changelog; the twin answers the
51
- page. The spec names an embedding's computed attribute `$embed_<attribute>`, the Write and Embedding pages
52
- `embed_<attribute>`; the twin answers the pages.
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.
53
50
  - **APIs the pages document and this spec omits, outside the count until modelled:** the asynchronous form of a copy
54
51
  (`Prefer: respond-async`, answered 202 with a `Location` to poll, https://turbopuffer.com/docs/auth "Asynchronous
55
52
  requests"), and the export read `GET /v1/namespaces/{namespace}` and `HEAD /v1/namespaces/{namespace}`, which the
@@ -1,4 +1,21 @@
1
1
  {
2
+ "https://raw.githubusercontent.com/turbopuffer/turbopuffer-typescript/v2.8.0/src/client.ts": {
3
+ "status": 200,
4
+ "checked": "2026-10-03",
5
+ "quotes": {
6
+ "baseURL = baseURL.replace('{region}', region);": true,
7
+ "https://{region}.turbopuffer.com": true,
8
+ "TURBOPUFFER_BASE_URL": true
9
+ }
10
+ },
11
+ "https://raw.githubusercontent.com/turbopuffer/turbopuffer-typescript/v2.8.0/src/core/error.ts": {
12
+ "status": 200,
13
+ "checked": "2026-10-03",
14
+ "quotes": {
15
+ "export class NotFoundError extends APIError<404, Headers> {}": true,
16
+ "export class AuthenticationError extends APIError<401, Headers> {}": true
17
+ }
18
+ },
2
19
  "https://raw.githubusercontent.com/turbopuffer/turbopuffer-typescript/v2.8.0/src/resources/namespaces.ts": {
3
20
  "status": 200,
4
21
  "checked": "2026-09-27"
@@ -11,6 +28,14 @@
11
28
  "The server returns `202 Accepted` with a `Location` header pointing to the operation.": true
12
29
  }
13
30
  },
31
+ "https://turbopuffer.com/docs/auth": {
32
+ "status": 200,
33
+ "checked": "2026-10-03",
34
+ "quotes": {
35
+ "all endpoints will return a JSON payload in the format": true,
36
+ "The HTTP API expects the API key to be formatted as a standard Bearer token and passed in the Authorization header:": true
37
+ }
38
+ },
14
39
  "https://turbopuffer.com/docs/branching.md": {
15
40
  "status": 200,
16
41
  "checked": "2026-09-27",
package/dist/src/fetch.js CHANGED
@@ -3,17 +3,11 @@
3
3
  import { createPackFetch } from '@volter/world-core';
4
4
  import surface from './generated/surface.gen.json' with { type: 'json' };
5
5
  import { manifest } from "./manifest.js";
6
- import { around } from "./semantics/around.js";
7
- import * as doors from "./semantics/doors.js";
8
6
  import { turbopufferSemantics } from "./semantics/index.js";
9
- import { screen as screen_dashboard } from "./screens/dashboard.js";
10
7
  export function createTurbopufferFetch(options = {}) {
11
8
  return createPackFetch({
12
9
  manifest,
13
10
  surface: surface,
14
11
  handlers: turbopufferSemantics,
15
- doors,
16
- around,
17
- screens: { "dashboard": screen_dashboard },
18
12
  }, options);
19
13
  }
@@ -1 +1 @@
1
- {"generatedBy":"scripts/derive-pack.ts","resources":{"_seq_api_key":{"actions":[],"states":{},"embeds":{}}}}
1
+ {"generatedBy":"scripts/derive-pack.ts","resources":{}}
package/dist/src/index.js CHANGED
@@ -1,8 +1,10 @@
1
- // @volter/twin-turbopuffer — the turbopuffer twin (Protocol 3). A fixed file: the descriptor is the manifest's.
1
+ // @volter/twin-turbopuffer — the turbopuffer twin (Protocol 3). A fixed file (create-pack): the descriptor is the manifest's, and the
2
+ // kernel derives the vendor-backed half from the generated surface, unless the manifest declares none (vendorBacked.none;
3
+ // architecture, "The real-system adapters").
2
4
  import { packOf, registerPack } from '@volter/world-core';
3
5
  import { manifest } from "./manifest.js";
6
+ import surface from './generated/surface.gen.json' with { type: 'json' };
4
7
  export { createTurbopufferFetch } from "./fetch.js";
5
8
  export { createTurbopufferTwinServer } from "./server.js";
6
9
  export { manifest };
7
- // The descriptor: twin-world's architecture, "The descriptor"; declared in manifest.ts.
8
- export const pack = registerPack(packOf(manifest));
10
+ export const pack = registerPack(packOf(manifest, surface));