@volter/world-runtime 2.0.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 (164) hide show
  1. package/LICENSE +202 -0
  2. package/dist/known-external-services.json +1108 -0
  3. package/dist/src/ancestry.d.ts +2 -0
  4. package/dist/src/ancestry.js +42 -0
  5. package/dist/src/app-url.d.ts +47 -0
  6. package/dist/src/app-url.js +239 -0
  7. package/dist/src/attach.d.ts +48 -0
  8. package/dist/src/attach.js +87 -0
  9. package/dist/src/branch.d.ts +20 -0
  10. package/dist/src/branch.js +65 -0
  11. package/dist/src/browser-proxy-cli.d.ts +2 -0
  12. package/dist/src/browser-proxy-cli.js +41 -0
  13. package/dist/src/ca-trust.d.ts +5 -0
  14. package/dist/src/ca-trust.js +64 -0
  15. package/dist/src/catalog.d.ts +31 -0
  16. package/dist/src/catalog.js +148 -0
  17. package/dist/src/changeset.d.ts +142 -0
  18. package/dist/src/changeset.js +570 -0
  19. package/dist/src/cli.d.ts +2 -0
  20. package/dist/src/cli.js +1262 -0
  21. package/dist/src/command-lifetime.d.ts +15 -0
  22. package/dist/src/command-lifetime.js +98 -0
  23. package/dist/src/configs.d.ts +18 -0
  24. package/dist/src/configs.js +119 -0
  25. package/dist/src/console-apart.d.ts +38 -0
  26. package/dist/src/console-apart.js +107 -0
  27. package/dist/src/consumers.d.ts +46 -0
  28. package/dist/src/consumers.js +200 -0
  29. package/dist/src/covers.d.ts +183 -0
  30. package/dist/src/covers.js +800 -0
  31. package/dist/src/fixture-env.d.ts +42 -0
  32. package/dist/src/fixture-env.js +221 -0
  33. package/dist/src/host-cli.d.ts +2 -0
  34. package/dist/src/host-cli.js +92 -0
  35. package/dist/src/host-fault-fixture.d.ts +32 -0
  36. package/dist/src/host-fault-fixture.js +100 -0
  37. package/dist/src/host-worker.d.ts +1 -0
  38. package/dist/src/host-worker.js +23 -0
  39. package/dist/src/host.d.ts +38 -0
  40. package/dist/src/host.js +135 -0
  41. package/dist/src/index.d.ts +48 -0
  42. package/dist/src/index.js +35 -0
  43. package/dist/src/infra-cli.d.ts +2 -0
  44. package/dist/src/infra-cli.js +136 -0
  45. package/dist/src/init.d.ts +227 -0
  46. package/dist/src/init.js +1117 -0
  47. package/dist/src/inject-map.d.ts +34 -0
  48. package/dist/src/inject-map.js +56 -0
  49. package/dist/src/lifecycle-record.d.ts +47 -0
  50. package/dist/src/lifecycle-record.js +196 -0
  51. package/dist/src/origin.d.ts +31 -0
  52. package/dist/src/origin.js +139 -0
  53. package/dist/src/pack-facts.d.ts +75 -0
  54. package/dist/src/pack-facts.js +98 -0
  55. package/dist/src/pglite-backing.d.ts +21 -0
  56. package/dist/src/pglite-backing.js +158 -0
  57. package/dist/src/pglite-host.mjs +147 -0
  58. package/dist/src/placeholder.d.ts +20 -0
  59. package/dist/src/placeholder.js +100 -0
  60. package/dist/src/prerequisites.d.ts +21 -0
  61. package/dist/src/prerequisites.js +49 -0
  62. package/dist/src/process-groups.d.ts +4 -0
  63. package/dist/src/process-groups.js +49 -0
  64. package/dist/src/project-inspect.d.ts +109 -0
  65. package/dist/src/project-inspect.js +827 -0
  66. package/dist/src/proxy-daemon.d.ts +2 -0
  67. package/dist/src/proxy-daemon.js +18 -0
  68. package/dist/src/redirect-proxy.d.ts +105 -0
  69. package/dist/src/redirect-proxy.js +665 -0
  70. package/dist/src/reflect.d.ts +74 -0
  71. package/dist/src/reflect.js +392 -0
  72. package/dist/src/resources.d.ts +26 -0
  73. package/dist/src/resources.js +22 -0
  74. package/dist/src/root.d.ts +114 -0
  75. package/dist/src/root.js +312 -0
  76. package/dist/src/run-task-worker.d.ts +1 -0
  77. package/dist/src/run-task-worker.js +38 -0
  78. package/dist/src/run-task.d.ts +18 -0
  79. package/dist/src/run-task.js +48 -0
  80. package/dist/src/runtime-test-support.d.ts +59 -0
  81. package/dist/src/runtime-test-support.js +205 -0
  82. package/dist/src/runtime.d.ts +256 -0
  83. package/dist/src/runtime.js +3502 -0
  84. package/dist/src/schema.d.ts +449 -0
  85. package/dist/src/schema.js +605 -0
  86. package/dist/src/serve.d.ts +30 -0
  87. package/dist/src/serve.js +82 -0
  88. package/dist/src/served-world.d.ts +194 -0
  89. package/dist/src/served-world.js +986 -0
  90. package/dist/src/service-exit.d.ts +46 -0
  91. package/dist/src/service-exit.js +195 -0
  92. package/dist/src/service-recorder.d.ts +1 -0
  93. package/dist/src/service-recorder.js +121 -0
  94. package/dist/src/sibling.d.ts +1 -0
  95. package/dist/src/sibling.js +9 -0
  96. package/dist/src/signals.d.ts +1 -0
  97. package/dist/src/signals.js +11 -0
  98. package/dist/src/storage-capacity.d.ts +8 -0
  99. package/dist/src/storage-capacity.js +61 -0
  100. package/dist/src/tail.d.ts +30 -0
  101. package/dist/src/tail.js +160 -0
  102. package/dist/src/tcp-port.d.ts +2 -0
  103. package/dist/src/tcp-port.js +36 -0
  104. package/dist/src/up-task-worker.d.ts +1 -0
  105. package/dist/src/up-task-worker.js +61 -0
  106. package/dist/src/up-task.d.ts +17 -0
  107. package/dist/src/up-task.js +49 -0
  108. package/dist/src/websocket-relay.d.ts +3 -0
  109. package/dist/src/websocket-relay.js +40 -0
  110. package/known-external-services.json +1108 -0
  111. package/package.json +83 -0
  112. package/src/ancestry.ts +36 -0
  113. package/src/app-url.ts +253 -0
  114. package/src/attach.ts +117 -0
  115. package/src/branch.ts +63 -0
  116. package/src/browser-proxy-cli.ts +44 -0
  117. package/src/ca-trust.ts +57 -0
  118. package/src/catalog.ts +156 -0
  119. package/src/changeset.ts +627 -0
  120. package/src/cli.ts +1111 -0
  121. package/src/command-lifetime.ts +79 -0
  122. package/src/configs.ts +110 -0
  123. package/src/console-apart.ts +90 -0
  124. package/src/consumers.ts +185 -0
  125. package/src/covers.ts +934 -0
  126. package/src/fixture-env.ts +230 -0
  127. package/src/host-cli.ts +90 -0
  128. package/src/host-worker.ts +23 -0
  129. package/src/host.ts +169 -0
  130. package/src/index.ts +171 -0
  131. package/src/infra-cli.ts +133 -0
  132. package/src/init.ts +1316 -0
  133. package/src/inject-map.ts +72 -0
  134. package/src/lifecycle-record.ts +168 -0
  135. package/src/origin.ts +134 -0
  136. package/src/pack-facts.ts +128 -0
  137. package/src/pglite-backing.ts +141 -0
  138. package/src/pglite-host.mjs +147 -0
  139. package/src/placeholder.ts +89 -0
  140. package/src/prerequisites.ts +66 -0
  141. package/src/process-groups.ts +33 -0
  142. package/src/project-inspect.ts +770 -0
  143. package/src/proxy-daemon.ts +21 -0
  144. package/src/redirect-proxy.ts +684 -0
  145. package/src/reflect.ts +440 -0
  146. package/src/resources.ts +22 -0
  147. package/src/root.ts +290 -0
  148. package/src/run-task-worker.ts +27 -0
  149. package/src/run-task.ts +44 -0
  150. package/src/runtime-test-support.ts +208 -0
  151. package/src/runtime.ts +3357 -0
  152. package/src/schema.ts +922 -0
  153. package/src/serve.ts +102 -0
  154. package/src/served-world.ts +812 -0
  155. package/src/service-exit.ts +175 -0
  156. package/src/service-recorder.ts +89 -0
  157. package/src/sibling.ts +10 -0
  158. package/src/signals.ts +10 -0
  159. package/src/storage-capacity.ts +60 -0
  160. package/src/tail.ts +205 -0
  161. package/src/tcp-port.ts +35 -0
  162. package/src/up-task-worker.ts +40 -0
  163. package/src/up-task.ts +45 -0
  164. package/src/websocket-relay.ts +32 -0
package/src/covers.ts ADDED
@@ -0,0 +1,934 @@
1
+ // `volter-world covers <world> --repo <path>` — the room-setup COVERAGE PROOF (the twin
2
+ // half of the "room ensure params" doctrine): check detected vendor and connection
3
+ // requirements against the named World. Static discovery is conservative and incomplete;
4
+ // an app scenario must verify behavior and consistency across interfaces.
5
+ //
6
+ // Detection (repo side) reuses inspect-project's signals: every package.json across the
7
+ // root + all workspace members (pnpm/yarn/npm/bun), mapped through SDK_TWINS, plus
8
+ // vendor-shaped env names in committed .env* files and direct literal fetch destinations
9
+ // in production source (a repo may use a vendor without declaring its SDK).
10
+ //
11
+ // Matching (world side) reads the world's INSTANCE when one exists (.volter/worlds/<name>/
12
+ // instance.json — the truth for a booted world) and falls back to the stable CONFIG
13
+ // (worlds/configs/<name>.json) so the proof also works pre-boot.
14
+ //
15
+ // LOUD FAILURE SEMANTICS — this is a proof, not a report:
16
+ // exit 0 ⇔ every detected vendor is covered AND nothing external-service-shaped is
17
+ // unaccounted for. A vendor with no twin in the world → MISSING → exit 1.
18
+ // A twin that IS in the world but that no traffic can reach (its service
19
+ // resolves to no injector vendor and exposes no app-read endpoint env — the
20
+ // LibreChat AWS_TWIN_URL trap) → UNINTERCEPTABLE → exit 1: presence is not
21
+ // coverage. An external-service-shaped dep/env var with no vendor mapping →
22
+ // unknown-sdk → exit 1 by default (`--allow-unknown` downgrades to a warning:
23
+ // unknowns still print, but stop failing the proof).
24
+
25
+ import { readFileSync } from 'node:fs';
26
+ import { dirname, join, resolve } from 'node:path';
27
+ import { fileURLToPath } from 'node:url';
28
+ import { loadWorldConfig } from './configs.ts';
29
+ import { injectableVendorKeys, loadInject, twinUrlVendorFor } from './inject-map.ts';
30
+ import { connectionProtocol, projectConnections, projectDependencies, projectEnvNames, projectFetchUrls, projectNpmRegistries, PYPI_TWINS, SDK_TWINS } from './project-inspect.ts';
31
+ import { overlayCoversMaps, packFacts } from './pack-facts.ts';
32
+ import { statusWorld } from './runtime.ts';
33
+ import { worldSelectionIncludes, type WorldSelection, type WorldServiceConfig, type WorldServiceInstance, type WorldUsage } from './schema.ts';
34
+
35
+ export type CoverageStatus = 'covered' | 'missing' | 'uninterceptable' | 'unknown-sdk' | 'acknowledged' | 'excluded';
36
+
37
+ export type CoverageRow = {
38
+ /** vendor key for mapped vendors; the raw dep/env name for unknown-sdk rows */
39
+ vendor: string;
40
+ /** how the repo betrayed the vendor, e.g. 'npm: stripe' / 'env: STRIPE_SECRET_KEY' */
41
+ detectedVia: string[];
42
+ /** Transport from pack metadata, or a separately required native connection. */
43
+ connection?: string;
44
+ /** the matching world service/env identifier when covered, else null */
45
+ twinInWorld: string | null;
46
+ status: CoverageStatus;
47
+ };
48
+
49
+ export type CoverageReport = {
50
+ world: string;
51
+ /** 'instance' when a booted/recorded instance was read; 'config' for the stable config */
52
+ worldSource: 'instance' | 'config';
53
+ worldPath: string;
54
+ repo: string;
55
+ twinsInWorld: string[];
56
+ rows: CoverageRow[];
57
+ covered: string[];
58
+ missing: string[];
59
+ /** vendors whose twin IS in the world but nothing can route vendor traffic to it (the
60
+ * service resolves to no injector vendor and exposes no app-read endpoint env) — the
61
+ * LibreChat AWS_TWIN_URL trap. Fails the proof: a twin nothing reaches covers nothing. */
62
+ uninterceptable: string[];
63
+ unknown: string[];
64
+ acknowledged: { vendor: string; reason: string }[];
65
+ excluded: string[];
66
+ allowUnknown: boolean;
67
+ ok: boolean;
68
+ };
69
+
70
+ /** identifiers are compared case/punctuation-insensitively: 's3', 'S3_TWIN_URL' stem,
71
+ * a 'stripe' service id and the 'ai-gateway' pack name all normalize cleanly. */
72
+ function normalizeId(text: string): string {
73
+ return text.toLowerCase().replace(/[^a-z0-9]/g, '');
74
+ }
75
+
76
+ /** Which world-side identifiers (normalized service ids / *_TWIN_URL stems / pack names)
77
+ * count as covering a vendor. Default: the vendor key itself. Extras cover the packs whose
78
+ * world identity differs from the SDK vendor key (the consolidated aws twin answers as
79
+ * s3/dynamodb/timestream; cookbook supabase worlds inject SUPABASE_MGMT_TWIN_URL). */
80
+ const VENDOR_WORLD_IDS: Record<string, string[]> = {
81
+ // (empty — every entry has moved onto its pack descriptor. See the note below.)
82
+ };
83
+
84
+ function worldIdsFor(vendor: string): string[] {
85
+ return VENDOR_WORLD_IDS[vendor] ?? [normalizeId(vendor)];
86
+ }
87
+
88
+
89
+ /**
90
+ * The INJECTOR vendor keys that can carry this vendor's traffic, in a stable order — the single
91
+ * source of truth for "can zero-edit interception work here, and under which `*_TWIN_URL` name?".
92
+ *
93
+ * Read from `@volter/world-core/inject`'s own VENDOR_HOSTS table (never a re-encoding of it), and
94
+ * filtered through the same `VENDOR_WORLD_IDS` aliasing the proof matches with: `aws` yields
95
+ * `['s3','dynamodb','timestream']` (the consolidated twin's real keys — `AWS_TWIN_URL` is the
96
+ * inert trap), `stripe` yields `['stripe']`, and a pack in vendor-hosts.test.ts's
97
+ * descriptor hostsNone ruling yields `[]`.
98
+ *
99
+ * Two callers, one answer: `covers` uses it to decide whether an UNINTERCEPTABLE finding is a
100
+ * fixable wiring bug (keys exist) or an acknowledgeable allowlist gap (none do), and `init` uses
101
+ * it to DERIVE the canonical `injectEnv` it emits — so an emitted world can never claim a
102
+ * `*_TWIN_URL` var the injector does not read.
103
+ */
104
+ export function injectorVendorKeysFor(vendor: string): string[] {
105
+ const worldIds = new Set(worldIdsFor(vendor));
106
+ return [...injectableVendorKeys()].filter((key) => worldIds.has(normalizeId(key)));
107
+ }
108
+
109
+ /** Shell-safe env name read by the injector for a vendor key, including hyphenated keys. */
110
+ export function injectorEnvNameForKey(key: string): string {
111
+ return `${key.toUpperCase().replace(/[^A-Z0-9]/g, '_')}_TWIN_URL`;
112
+ }
113
+
114
+ /** Vendor-shaped env var detection (the secondary signal). The var must end in a
115
+ * credential/endpoint suffix; the remaining stem (framework prefixes stripped,
116
+ * normalized) is looked up here. */
117
+ // Exported for scripts/packless-claims.test.ts, which checks the packless registry against
118
+ // the OVERLAID map (legacy entries + descriptor adoption.envStems in one view) — importing
119
+ // the real map is unbreakable by formatting, unlike the source-parsing it replaced (§9
120
+ // skeptic M3, 2026-08-31: a reflow or quote-style change silently emptied the parsed set).
121
+ export const ENV_STEM_VENDORS: Record<string, string> = {
122
+ // (empty — every entry has moved onto its pack descriptor. See the note below.)
123
+ };
124
+
125
+ const ENV_FRAMEWORK_PREFIX = /^(NEXT_PUBLIC_|VITE_|REACT_APP_|EXPO_PUBLIC_|NUXT_PUBLIC_|PUBLIC_)/;
126
+
127
+ /** Broad credential/endpoint suffixes — used to derive a stem for KNOWN-vendor detection
128
+ * (a false stem is harmless: it only counts when the stem hits ENV_STEM_VENDORS). */
129
+ const ENV_SUFFIX_BROAD =
130
+ /_(ACCESS_KEY_ID|SECRET_ACCESS_KEY|SERVICE_ROLE_KEY|PUBLISHABLE_KEY|WEBHOOK_SECRET|SIGNING_SECRET|CLIENT_SECRET|CLIENT_ID|CONSUMER_KEY|ACCOUNT_SID|OAUTH_TOKEN|AUTH_TOKEN|ACCESS_TOKEN|BEARER_TOKEN|BOT_TOKEN|API_TOKEN|API_SECRET|API_KEY|APIKEY|SECRET_KEY|API_URL|BASE_URL|REST_URL|SECRET|TOKEN|KEY|DSN)$/;
131
+
132
+ /** Narrow, unmistakably vendor-shaped suffixes — a var with one of these whose stem maps
133
+ * to NO known vendor is an unknown external service and fails the proof. (Deliberately
134
+ * excludes bare _SECRET/_TOKEN/_KEY: JWT_SECRET / SESSION_SECRET are app-local. _REST_URL
135
+ * is here on purpose: it is a hosted-service endpoint shape — UPSTASH_REDIS_REST_URL
136
+ * produced NO row at all in the Dub blind-adoption run. _CLIENT_ID/_CLIENT_SECRET/
137
+ * _CONSUMER_KEY are here on purpose too: they are the OAuth-app credential shape, and
138
+ * before they were strict the Cal.com blind run silently dropped NINE OAuth vendors —
139
+ * ZOOM_CLIENT_ID, MS_GRAPH_CLIENT_SECRET, SALESFORCE_CONSUMER_KEY, GOOGLE_CLIENT_ID, … —
140
+ * from a proof that exited 0. The env-detection heuristic was structurally biased against
141
+ * exactly the vendor class integration-heavy apps are made of.) */
142
+ const ENV_SUFFIX_STRICT = /_(API_KEY|APIKEY|API_TOKEN|API_SECRET|OAUTH_TOKEN|CLIENT_ID|CLIENT_SECRET|CONSUMER_KEY|ACCOUNT_SID|DSN|REST_URL)$/;
143
+
144
+ /** App-local stems that must never be flagged as an unknown vendor. `redis` is deliberately
145
+ * NOT here: a redis-stemmed var only reaches this lookup through a vendor-shaped suffix
146
+ * (e.g. REDIS_REST_URL — hosted Redis, an external service), while plain local-Redis vars
147
+ * (REDIS_URL, REDIS_HOST, REDIS_PASSWORD) never match ENV_SUFFIX_STRICT in the first place. */
148
+ const ENV_STEM_IGNORE = new Set([
149
+ 'jwt', 'session', 'auth', 'nextauth', 'app', 'api', 'admin', 'internal', 'server', 'client',
150
+ 'cookie', 'csrf', 'encryption', 'webhook', 'test', 'dev', 'local', 'demo', 'example', 'my',
151
+ 'database', 'db', 'postgres', 'mysql', 'mongo', 'smtp', 'volter', 'twin', 'world',
152
+ // generic IdP-config stems: OAUTH_CLIENT_ID / OIDC_CLIENT_SECRET name a PROTOCOL role, not a
153
+ // vendor — now that _CLIENT_ID/_CLIENT_SECRET are strict suffixes these would otherwise raise
154
+ // a false unknown-vendor alarm on every app with a generic OAuth config block. Vendor-named
155
+ // stems (ZOOM_, SALESFORCE_, GOOGLE_, …) still surface.
156
+ 'oauth', 'oidc',
157
+ ]);
158
+
159
+ function envVendorStem(name: string, suffix: RegExp): string | null {
160
+ const stripped = name.replace(ENV_FRAMEWORK_PREFIX, '');
161
+ const match = stripped.match(suffix);
162
+ if (!match || match.index === undefined || match.index === 0) return null;
163
+ return normalizeId(stripped.slice(0, match.index));
164
+ }
165
+
166
+ /** Is this env NAME shaped like a CREDENTIAL/endpoint at all (any broad vendor suffix)? The
167
+ * question `init` asks before deciding whether a value in a repo's `.env.example` may be copied
168
+ * verbatim: `APP_NAME` may, `ANYTHING_SECRET` may not — a committed example file is exactly where
169
+ * live keys hide (the ponder blind-adoption run found real ones), so a credential-shaped name is
170
+ * ALWAYS replaced by a fake, whether or not its stem maps to a vendor this repo twins. Exported
171
+ * from here so the emission path and the proof read ONE definition of "credential-shaped". */
172
+ export function isCredentialShapedEnvName(name: string): boolean {
173
+ return ENV_SUFFIX_BROAD.test(name.replace(ENV_FRAMEWORK_PREFIX, ''));
174
+ }
175
+
176
+ /** The vendor a credential-shaped env NAME betrays, or null. Same broad-suffix route the
177
+ * coverage proof's secondary signal uses (`STRIPE_SECRET_KEY` → 'stripe'). */
178
+ export function envNameVendor(name: string): string | null {
179
+ // ⚠️ This deliberately does NOT claim the SMTP host/URL vars, even though `detectRepoVendors`
180
+ // below detects them as vendor `smtp`. The two functions answer DIFFERENT questions, and §9
181
+ // found both halves of that the hard way:
182
+ // • round 1 called the divergence an inconsistency ("one answer per name");
183
+ // • round 2 showed what happens when you remove it. This function's only caller is `init`'s
184
+ // env emission (`init.ts`), which REPLACES a credential-shaped value with `twin-fake-<name>`.
185
+ // Claiming `SMTP_URL`/`EMAIL_SERVER` here turned NextAuth's `smtp://user:pass@host:port` into
186
+ // `twin-fake-email-server`, which `new URL(...)` cannot parse — breaking the app to protect a
187
+ // value that was never a credential in the first place.
188
+ // So: this asks "is this name a VENDOR CREDENTIAL that must be faked?" (a hostname is not), while
189
+ // `detectRepoVendors` asks "which vendors does this repo talk to?" (the mail path certainly is
190
+ // one). Same string, two honest answers.
191
+ const stem = envVendorStem(name, ENV_SUFFIX_BROAD);
192
+ return stem === null ? null : ENV_STEM_VENDORS[stem] ?? null;
193
+ }
194
+
195
+ /** SMTP-shaped env names — the raw-protocol mail path (nodemailer et al.) the HTTP-vendor
196
+ * heuristics above are structurally blind to. The Cal.com blind run's booking-confirmation
197
+ * mail (EMAIL_SERVER_HOST/EMAIL_SERVER_PORT) was invisible to the proof while being the
198
+ * single most important vendor touchpoint of the app. Conservative stem+suffix approach:
199
+ * only the HOST/URL forms count (`SMTP_HOST`, `MAILGUN_SMTP_HOST`, `SMTP_URL`, and
200
+ * NextAuth/nodemailer's `EMAIL_SERVER`/`EMAIL_SERVER_HOST` connection forms) — a bare
201
+ * SMTP_USER/_PASSWORD without a host proves nothing and would duplicate rows.
202
+ *
203
+ * This signal used to surface as unknown-sdk ('smtp') because no SMTP twin existed — the honest
204
+ * outcome at the time. The `smtp` pack now twins the protocol, so it is a DETECTED vendor and a
205
+ * world that runs an smtp service covers it. What has NOT changed is why the signal has to be a
206
+ * dedicated route at all: SMTP is intercepted through the app-read env name itself, not through a
207
+ * host the injector rewrites, so the env var IS the touchpoint rather than a hint about one.
208
+ * (The 'smtp' entry in ENV_STEM_IGNORE guards the generic-suffix stem route; this signal is
209
+ * deliberate and separate.) */
210
+ function isSmtpEnvSignal(name: string): boolean {
211
+ const stripped = name.replace(ENV_FRAMEWORK_PREFIX, '');
212
+ return /(^|_)SMTP_(HOST|URL)$/.test(stripped) || /^EMAIL_SERVER(_HOST)?$/.test(stripped);
213
+ }
214
+
215
+ /** npm scopes whose EVERY package is one vendor's client surface — an unmapped
216
+ * satellite package (`@sentry/cli`, `@datadog/browser-logs`, `@octokit/graphql`)
217
+ * still detects (and is covered by) that vendor's twin. Deliberately NOT `@aws-sdk`
218
+ * or `@azure`/`@google-cloud`: those scopes span many services and the consolidated
219
+ * twins only model some of them — unmapped clients there must stay unknown-sdk. */
220
+ const SDK_SCOPE_VENDORS: Record<string, string> = {
221
+ // (empty — every entry has moved onto its pack descriptor. See the note below.)
222
+ };
223
+ // descriptor-first migration (adding-a-twin.md §3), COMPLETE for these three tables: every pack declares its own
224
+ // scopes / env stems / world ids (`adoption` on its descriptor, compiled into the committed
225
+ // pack-facts artifact), and all three literals above are now empty — they are populated entirely
226
+ // by the overlay below. They are kept as the overlay's targets, not as homes: the object identity
227
+ // is what every use site already reads, so nothing downstream changed. Do NOT re-add an entry
228
+ // here; a fact declared in both homes throws at module init.
229
+ overlayCoversMaps({ scopeVendors: SDK_SCOPE_VENDORS, envStemVendors: ENV_STEM_VENDORS, vendorWorldIds: VENDOR_WORLD_IDS });
230
+
231
+ export function scopeVendorFor(name: string): string | undefined {
232
+ const entry = Object.entries(SDK_SCOPE_VENDORS).find(([prefix]) => name === prefix || name.startsWith(prefix));
233
+ return entry?.[1];
234
+ }
235
+
236
+ /** npm scopes holding at least one twin-mapped package (from SDK_TWINS' scoped keys and
237
+ * SDK_SCOPE_VENDORS). An UNMAPPED sibling from such a scope is almost always another external
238
+ * surface of the same platform — in the Dub blind-adoption run, `@upstash/redis` and
239
+ * `@upstash/ratelimit` produced NO row at all while `@upstash/qstash` was mapped, a silent
240
+ * blind spot. Such siblings surface as unknown-sdk instead of disappearing. */
241
+ const MAPPED_SCOPES: ReadonlySet<string> = new Set(
242
+ [...Object.keys(SDK_TWINS), ...Object.keys(SDK_SCOPE_VENDORS)]
243
+ .filter((name) => name.startsWith('@'))
244
+ .map((name) => `${name.split('/')[0]}/`),
245
+ );
246
+
247
+ export function isMappedScopeSibling(name: string): boolean {
248
+ if (knownExternalServices().notExternal[name] !== undefined) return false;
249
+ return [...MAPPED_SCOPES].some((scope) => name.startsWith(scope));
250
+ }
251
+
252
+ /**
253
+ * THE PACKLESS-VENDOR REGISTRY — `known-external-services.json`, shipped inside this package.
254
+ * ONE home for the knowledge that used to live in three inline sets here (NOT_AN_EXTERNAL_
255
+ * SERVICE, UNKNOWN_DEP_KNOWN_SERVICES, UNKNOWN_DEP_PATTERNS) plus the 2026-08-31 census
256
+ * rulings: `deps`/`envStems` are external-service signals the catalog KNOWS but has no pack
257
+ * for (`disposition: 'demanded'` stays a LOUD coverage gap — the demand queue;
258
+ * `'acknowledged'` was adjudicated acceptable and auto-acknowledges with its recorded
259
+ * reason); `notExternal` suppresses vendor-adjacent glue (protocol/type/UI helpers, auth
260
+ * libraries); `patterns` are the external-shape heuristics. AN ENTRY DIES THE DAY ITS PACK
261
+ * IS BORN — scripts/packless-claims.test.ts enforces disjointness with pack adoption and
262
+ * SDK_TWINS (the `@planetscale/database`/twin#255 lesson, mechanized). Lazy + cached like
263
+ * pack-facts.ts's loader — though note this module ALREADY does module-scope I/O via the
264
+ * overlayCoversMaps call below, so laziness here is consistency, not a load-bearing
265
+ * invariant (§9 round two L1).
266
+ */
267
+ export type PacklessDisposition = 'demanded' | 'acknowledged';
268
+ export type PacklessEntry = { disposition: PacklessDisposition; reason: string };
269
+ export type KnownExternalServices = {
270
+ deps: Record<string, PacklessEntry>;
271
+ envStems: Record<string, PacklessEntry>;
272
+ notExternal: Record<string, string>;
273
+ patterns: Array<{ pattern: string; reason: string }>;
274
+ };
275
+
276
+ let registryCache: KnownExternalServices | undefined;
277
+ export function knownExternalServices(): KnownExternalServices {
278
+ if (registryCache === undefined) {
279
+ const path = join(dirname(fileURLToPath(import.meta.url)), '..', 'known-external-services.json');
280
+ registryCache = JSON.parse(readFileSync(path, 'utf8')) as KnownExternalServices;
281
+ }
282
+ return registryCache;
283
+ }
284
+
285
+ let patternCache: RegExp[] | undefined;
286
+ function unknownDepPatterns(): RegExp[] {
287
+ patternCache ??= knownExternalServices().patterns.map((p) => new RegExp(p.pattern));
288
+ return patternCache;
289
+ }
290
+
291
+ function isExternalServiceShapedDep(name: string): boolean {
292
+ const registry = knownExternalServices();
293
+ if (registry.notExternal[name] !== undefined) return false;
294
+ if (registry.deps[name] !== undefined) return true;
295
+ return unknownDepPatterns().some((pattern) => pattern.test(name));
296
+ }
297
+
298
+ /** The registry's STANDING acknowledgment for an unknown-signal name (npm dep or env stem),
299
+ * or null when the signal is unlisted or listed as a demanded (loud) gap. Exported for init,
300
+ * whose plan partitions the same signals the proof does.
301
+ *
302
+ * DEMANDED ANYWHERE WINS: the unknown map merges npm deps, env stems and registry-host ids
303
+ * under one key space, so a name listed in BOTH registry sections must never let one
304
+ * section's acknowledgment quiet the other's demanded gap (§9 round two H5, 2026-08-31: an
305
+ * acknowledged dep entry silently green-lit a repo whose only signal was the same-named
306
+ * DEMANDED env stem). Loud beats quiet; the gate also refuses conflicting dispositions. */
307
+ export function registryAcknowledgedReason(name: string): string | null {
308
+ const registry = knownExternalServices();
309
+ const entries = [registry.deps[name], registry.envStems[name]].filter(
310
+ (entry): entry is PacklessEntry => entry !== undefined,
311
+ );
312
+ if (entries.length === 0 || entries.some((entry) => entry.disposition !== 'acknowledged')) return null;
313
+ return entries[0]!.reason;
314
+ }
315
+
316
+ export type WorldTwinId = {
317
+ /** display label (e.g. 'stripe (twin service)') */
318
+ label: string;
319
+ /** whether traffic can actually REACH the twin behind this identifier: the injector/proxy
320
+ * intercepts its vendor hosts, or the service exposes app-read endpoint env. A twin that is
321
+ * merely present — reachable by nothing — must not count as coverage (the LibreChat
322
+ * AWS_TWIN_URL trap: the injectEnv looked wired but the injector reads no `aws` vendor). */
323
+ interceptable: boolean;
324
+ };
325
+
326
+ type WorldTwinInventory = {
327
+ source: 'instance' | 'config';
328
+ path: string;
329
+ /** normalized identifier → id record (e.g. 'stripe' → { label: 'stripe (service)', … }) */
330
+ ids: Map<string, WorldTwinId>;
331
+ connections: Map<string, { protocol: string | null; label: string }>;
332
+ /** Saved policy at boot/config time; absent means legacy all-signals coverage. */
333
+ selection?: WorldSelection;
334
+ declared: Map<string, WorldTwinId>;
335
+ };
336
+
337
+ function declaredTwin(services: Array<WorldServiceConfig | WorldServiceInstance>): Map<string, WorldTwinId> {
338
+ const declared = new Map<string, WorldTwinId>();
339
+ for (const service of services) {
340
+ if (service.type !== undefined && service.type !== 'twin') continue;
341
+ const config = service as WorldServiceConfig;
342
+ const identity = config.package?.match(/^@volter\/twin-(.+)$/)?.[1] ?? servicePackNames(config)[0] ?? service.id;
343
+ const vendor = Object.keys(packFacts()).find((candidate) => worldIdsFor(candidate).includes(normalizeId(identity))) ?? identity;
344
+ const ids = new Map<string, WorldTwinId>();
345
+ addServiceIds(ids, service);
346
+ const match = [...worldIdsFor(vendor), vendor].map(normalizeId).map((id) => ids.get(id)).find(Boolean);
347
+ declared.set(vendor, match ?? { label: `${service.id} (declared twin)`, interceptable: false });
348
+ }
349
+ return declared;
350
+ }
351
+
352
+ function addId(ids: Map<string, WorldTwinId>, key: string, label: string, interceptable: boolean): void {
353
+ const existing = ids.get(key);
354
+ if (!existing) ids.set(key, { label, interceptable });
355
+ // first label wins (stable output), but interceptability is an OR across contributors: a
356
+ // second service that CAN be reached upgrades the id.
357
+ else if (interceptable && !existing.interceptable) existing.interceptable = true;
358
+ }
359
+
360
+ function servicePackNames(service: { package?: string; command?: string | string[]; args?: string[]; colocate?: { module?: string } }): string[] {
361
+ const commandParts = [
362
+ ...(service.package ? [service.package] : []),
363
+ ...(Array.isArray(service.command) ? service.command : service.command ? [service.command] : []),
364
+ ...(service.args ?? []),
365
+ ...(service.colocate?.module ? [service.colocate.module] : []),
366
+ ];
367
+ return commandParts.flatMap((part) => {
368
+ const fromPath = part.match(/packages\/twin\/([a-z0-9-]+)\//);
369
+ const fromBin = part.match(/^world-([a-z0-9-]+)$/);
370
+ const fromPkg = part.match(/(?:^|[/\\])@volter\/twin-([a-z0-9-]+)(?:[/\\]|$)/);
371
+ return [fromPath?.[1], fromBin?.[1], fromPkg?.[1]].filter((name): name is string => name !== undefined);
372
+ });
373
+ }
374
+
375
+ /** Endpoint wiring owned by a service, never a random URL from global config/env. Config
376
+ * templates must use the service's allocated host/port. Instance values must point at that
377
+ * listener, or have been discovered by the external lifecycle. HTTP pack facts veto native
378
+ * coverage even when someone has put a mysql:// template on an HTTP twin. */
379
+ function serviceConnections(
380
+ services: Array<WorldServiceConfig | WorldServiceInstance>,
381
+ effectiveEnv?: Record<string, string>,
382
+ ): WorldTwinInventory['connections'] {
383
+ const bindings: WorldTwinInventory['connections'] = new Map();
384
+ for (const service of services) {
385
+ const instance = 'pid' in service;
386
+ const config = instance ? undefined : service;
387
+ const facts = servicePackNames(service).map((name) => packFacts()[name]).filter((fact) => fact !== undefined);
388
+ if (!instance && config?.injectEnv) bindings.set(config.injectEnv, { protocol: 'http', label: `${service.id} (${config.injectEnv})` });
389
+ const values = instance ? service.env : config?.injectEnvTemplates ?? {};
390
+ for (const [name, value] of Object.entries(values)) {
391
+ const protocol = connectionProtocol(value);
392
+ const command = [...(Array.isArray(service.command) ? service.command : []), ...('args' in service ? service.args ?? [] : [])];
393
+ // The pack-transport veto is about NATIVE schemes (a mysql:// template on an HTTP twin); an
394
+ // http(s) endpoint template on any twin is that twin's own HTTP door.
395
+ const incompatiblePack = protocol !== null && facts.some((fact) => {
396
+ if (fact.nativeTransport?.protocol === protocol && command.includes(fact.nativeTransport.flag)) return false;
397
+ return fact.transport !== 'raw-tcp' || !Object.values(fact.endpointEnv?.templates ?? {})
398
+ .some((template) => connectionProtocol(template) === protocol && protocol !== null);
399
+ });
400
+ let routed = false;
401
+ if (protocol !== null && !incompatiblePack) {
402
+ if (instance) {
403
+ if (effectiveEnv?.[name] !== value) continue; // another service/env replaced this binding
404
+ if (service.type === 'external') routed = service.external?.discoveredEnv?.[name] === value;
405
+ else {
406
+ try {
407
+ const url = new URL(value);
408
+ routed = ['localhost', '127.0.0.1', '[::1]'].includes(url.hostname) && Number(url.port) === service.port;
409
+ } catch { /* unresolved connection stays unknown */ }
410
+ }
411
+ } else if (config?.port !== undefined) {
412
+ try {
413
+ const url = new URL(value.replaceAll('${host}', '127.0.0.1').replaceAll('${port}', '54321'));
414
+ routed = url.hostname === '127.0.0.1' && url.port === '54321' &&
415
+ /^\w[\w+.-]*:\/\/(?:[^/?#]*@)?\$\{host\}:\$\{port\}(?:[/?#]|$)/.test(value);
416
+ } catch { /* unresolved connection stays unknown */ }
417
+ }
418
+ }
419
+ bindings.set(name, { protocol: routed ? protocol : incompatiblePack ? 'incompatible' : /^https?:/.test(value) ? 'http' : null, label: `${service.id} (${name})` });
420
+ }
421
+
422
+ if (!instance) {
423
+ // Runtime applies CLI redirects last; their ${url} is always the HTTP listener.
424
+ for (const [name, template] of Object.entries(config?.cliRedirect ?? {})) {
425
+ bindings.set(name, { protocol: template.includes('${url}') || /^https?:/.test(template) ? 'http' : null, label: `${service.id} (${name}; cliRedirect)` });
426
+ }
427
+ for (const mapping of config?.external?.discover ?? []) {
428
+ bindings.set(mapping.as, { protocol: null, label: `${service.id} (${mapping.as}; discover after up)` });
429
+ }
430
+ }
431
+ }
432
+ return bindings;
433
+ }
434
+
435
+ function addServiceIds(
436
+ ids: Map<string, WorldTwinId>,
437
+ service: {
438
+ id: string;
439
+ type?: string;
440
+ injectEnv?: string;
441
+ injectEnvTemplates?: Record<string, string>;
442
+ cliRedirect?: unknown;
443
+ /** instance-path services carry their injected vars here instead of the config fields */
444
+ env?: Record<string, string>;
445
+ command?: string | string[];
446
+ args?: string[];
447
+ package?: string;
448
+ colocate?: { module?: string };
449
+ },
450
+ ): void {
451
+ const type = service.type ?? 'twin';
452
+ const packNames = servicePackNames(service);
453
+ // How would traffic actually reach this twin?
454
+ // • the injector/ambient proxy intercepts its vendor hosts — true when its injectEnv is a
455
+ // `*_TWIN_URL` var the injector reads, or its service id / pack name IS an injector
456
+ // vendor key (the consolidated aws twin's `s3` service id, for example);
457
+ // • OR the app/CLI reads its endpoint env directly — external services (discovered env),
458
+ // injectEnvTemplates (LIVEKIT_URL=…), cliRedirect, or a non-`*_TWIN_URL` injectEnv.
459
+ // A twin service with NEITHER is present but unreachable: interceptable=false.
460
+ const vendorKeys = new Set([...injectableVendorKeys()].map(normalizeId));
461
+ const envKeys = Object.keys(service.env ?? {}); // instance-path evidence of the same wiring
462
+ const injectorReads =
463
+ (service.injectEnv !== undefined && twinUrlVendorFor(service.injectEnv) !== null) ||
464
+ envKeys.some((key) => twinUrlVendorFor(key) !== null);
465
+ const appConfigured =
466
+ type === 'external' ||
467
+ service.cliRedirect !== undefined ||
468
+ Object.keys(service.injectEnvTemplates ?? {}).length > 0 ||
469
+ (service.injectEnv !== undefined && !/_TWIN_URL$/.test(service.injectEnv)) ||
470
+ envKeys.some((key) => !/_TWIN_URL$/.test(key));
471
+ const hostMatched =
472
+ vendorKeys.has(normalizeId(service.id)) || packNames.some((pack) => vendorKeys.has(normalizeId(pack)));
473
+ const endpointValues = [...Object.values(service.env ?? {}), ...Object.values(service.injectEnvTemplates ?? {})];
474
+ // Native infrastructure can share a vendor name with an HTTP pack. Identity alone must not
475
+ // turn its database listener into that vendor's HTTP API (e.g. PlanetScale's two clients).
476
+ const vendor = Object.keys(packFacts()).find((name) => worldIdsFor(name).includes(normalizeId(service.id)));
477
+ const facts = vendor === undefined ? undefined : packFacts()[vendor];
478
+ const httpNames = new Set([
479
+ ...(vendor === undefined ? [] : injectorVendorKeysFor(vendor).map(injectorEnvNameForKey)),
480
+ ...(facts?.endpointEnv ? [facts.endpointEnv.name, ...Object.keys(facts.endpointEnv.templates ?? {})] : []),
481
+ ]);
482
+ const vendorHttpEndpoint = Object.entries({ ...(service.env ?? {}), ...(service.injectEnvTemplates ?? {}) })
483
+ .some(([name, value]) => httpNames.has(name) && (/^(?:https?|wss?):/.test(value) || value === '${url}'));
484
+ const nativeOnly = packNames.length === 0 && endpointValues.some((value) => connectionProtocol(value) !== null) &&
485
+ !vendorHttpEndpoint;
486
+ const nativeMode = packNames.some((name) => {
487
+ const mode = packFacts()[name]?.nativeTransport;
488
+ return mode && [...(Array.isArray(service.command) ? service.command : []), ...(service.args ?? [])].includes(mode.flag);
489
+ });
490
+ const interceptable = !nativeOnly && !nativeMode && (injectorReads || appConfigured || hostMatched);
491
+ // twin + external services cover their vendor by identity; a plain 'process'
492
+ // service only counts via an explicit twin marker (injectEnv/*_TWIN_URL, pack path).
493
+ if (type === 'twin' || type === 'external') {
494
+ const label = type === 'twin' ? `${service.id} (twin service)` : `${service.id} (external service)`;
495
+ addId(ids, normalizeId(service.id), label, interceptable);
496
+ }
497
+ if (service.injectEnv) {
498
+ const stem = service.injectEnv.match(/^(.+)_TWIN_URL$/);
499
+ if (stem) addId(ids, normalizeId(stem[1]!), `${service.id} (${service.injectEnv})`, interceptable);
500
+ }
501
+ for (const pack of packNames) {
502
+ addId(ids, normalizeId(pack), `${service.id} (pack ${pack})`, interceptable);
503
+ }
504
+ }
505
+
506
+ /** The twins actually IN the named world: instance first (the booted truth), stable
507
+ * config as the pre-boot fallback. Throws loudly when the world resolves to neither. */
508
+ export function worldTwinInventory(world: string, root: string): WorldTwinInventory {
509
+ let instanceError: string | undefined;
510
+ try {
511
+ const status = statusWorld(world, root, { readOnly: true });
512
+ const ids = new Map<string, WorldTwinId>();
513
+ for (const service of Object.values(status.services)) addServiceIds(ids, service);
514
+ for (const key of Object.keys(status.env)) {
515
+ const stem = key.match(/^(.+)_TWIN_URL$/);
516
+ // a bare env `*_TWIN_URL` var is only a REACHABLE twin when the injector reads it
517
+ if (stem) addId(ids, normalizeId(stem[1]!), `env ${key}`, twinUrlVendorFor(key) !== null);
518
+ }
519
+ return { source: 'instance', path: `${status.dirs.instance}/instance.json`, ids, connections: serviceConnections(Object.values(status.services), status.env), selection: status.selection, declared: declaredTwin(Object.values(status.services)) };
520
+ } catch (error) {
521
+ instanceError = error instanceof Error ? error.message : String(error);
522
+ }
523
+ try {
524
+ const { path, config } = loadWorldConfig(world, root);
525
+ const ids = new Map<string, WorldTwinId>();
526
+ for (const service of config.services as WorldServiceConfig[]) addServiceIds(ids, service);
527
+ return { source: 'config', path, ids, connections: serviceConnections(config.services), selection: config.selection, declared: declaredTwin(config.services) };
528
+ } catch (error) {
529
+ const configError = error instanceof Error ? error.message : String(error);
530
+ throw new Error(
531
+ `volter-world covers: world "${world}" not found as an instance or a config.\n` +
532
+ ` instance: ${instanceError}\n config: ${configError}`,
533
+ );
534
+ }
535
+ }
536
+
537
+ export type CoverageOptions = {
538
+ root?: string;
539
+ allowUnknown?: boolean;
540
+ /**
541
+ * vendor → reason: vendors the operator ACKNOWLEDGES need no twin in this world — e.g. an SDK
542
+ * used verifier-only (svix's Webhook verifies incoming signatures locally and never calls out).
543
+ * An acknowledged vendor downgrades missing/unknown-sdk to status 'acknowledged' (reason shown,
544
+ * never silent); a reason is REQUIRED — an empty one throws.
545
+ *
546
+ * UNINTERCEPTABLE splits in two (the Cal.com svix finding):
547
+ * • an injector vendor key EXISTS for the vendor and the wiring is merely wrong (the LibreChat
548
+ * AWS_TWIN_URL trap) — a config bug, NOT acknowledgeable: the acknowledgment is refused
549
+ * loudly on the row and the proof stays red until the wiring is fixed;
550
+ * • NO injector key exists at all (the pack is in its descriptor's hostsNone ruling
551
+ * allowlist — ~15 packs wire by explicit endpoint config only) — acknowledgeable WITH a
552
+ * reason. Before this, the only route to green was DELETING the twin from the world and
553
+ * acknowledging it as un-twinned, which made the config LESS truthful than the red proof.
554
+ */
555
+ acknowledge?: Record<string, string>;
556
+ };
557
+
558
+ /** What a repo BETRAYS about the external services it talks to — the repo half of the coverage
559
+ * proof, split out so `init` (which must EMIT a twin per detected vendor) and `covers` (which must
560
+ * PROVE one exists) can never drift apart by re-encoding detection twice. */
561
+ export type RepoVendorSignals = {
562
+ /** vendor key → the sources that betrayed it (`npm: stripe`, `env: STRIPE_SECRET_KEY`,
563
+ * `fetch: src/billing.ts:12 -> api.stripe.com`) */
564
+ detected: Map<string, string[]>;
565
+ /** external-service-shaped signal with NO vendor mapping → its sources (dep name, or env stem) */
566
+ unknown: Map<string, string[]>;
567
+ uses: Map<string, Array<{ usage: WorldUsage; evidence: string }>>;
568
+ unknownUses: Map<string, Array<{ usage: WorldUsage; evidence: string }>>;
569
+ };
570
+
571
+ function evidenceUsage(vendor: string, evidence: string): WorldUsage {
572
+ if (evidence.startsWith('dependency-tool:') || evidence.startsWith('registry:') || (vendor === 'npm-registry' && evidence === 'env: NPM_TOKEN')) return 'dependencies';
573
+ if (evidence.startsWith('build-tool:')) return 'build';
574
+ if (evidence.startsWith('deployment-tool:')) return 'deployment';
575
+ return 'application';
576
+ }
577
+
578
+ function usesOf(signals: Map<string, string[]>): Map<string, Array<{ usage: WorldUsage; evidence: string }>> {
579
+ return new Map([...signals].map(([vendor, evidence]) => {
580
+ const toolUsages = [...new Set(evidence
581
+ .filter((item) => item.startsWith('build-tool:') || item.startsWith('deployment-tool:'))
582
+ .map((item) => evidenceUsage(vendor, item)))];
583
+ const hasApplicationEvidence = evidence.some((item) => !item.startsWith('env:') && evidenceUsage(vendor, item) === 'application');
584
+ return [vendor, evidence.flatMap((item) => {
585
+ // A credential beside a declared vendor tool supports that tool unless the repo also has
586
+ // independent application evidence. The credential name alone cannot turn Wrangler into
587
+ // an application dependency; an SDK/fetch signal still records the application use too.
588
+ if (item.startsWith('env:') && !hasApplicationEvidence && toolUsages.length) {
589
+ return toolUsages.map((usage) => ({ usage, evidence: item }));
590
+ }
591
+ return [{ usage: evidenceUsage(vendor, item), evidence: item }];
592
+ })];
593
+ }));
594
+ }
595
+
596
+ /** Detect every vendor (and every unmapped external-service-shaped signal) an application repo
597
+ * betrays: mapped npm dependencies across the root + all workspace members, vendor-shaped env
598
+ * names in committed `.env*` files, the SMTP/raw-protocol signal, and literal vendor URLs passed
599
+ * directly to fetch in production source. URL attribution reads the injector's VENDOR_HOSTS table
600
+ * rather than re-encoding host rules here. Insertion order follows the sorted dependency, env-name,
601
+ * and source lists, so callers that preserve it are deterministic. */
602
+ export function detectRepoVendors(repoPath: string): RepoVendorSignals {
603
+ const repo = resolve(repoPath);
604
+ // the platform's own packages — the twins an app installed, the command, the runtime — are
605
+ // never a vendor signal: an app that installed @volter/twin-slack did not gain a Slack dependency
606
+ const dependencies = projectDependencies(repo).filter((dep) => !dep.startsWith('@volter/') && !dep.startsWith('pypi:volter'));
607
+ const envNames = projectEnvNames(repo);
608
+ const npmRegistries = projectNpmRegistries(repo);
609
+
610
+ // vendor → detection sources
611
+ const detected = new Map<string, string[]>();
612
+ const mappedDeps = new Set<string>();
613
+ const tools = new Map<string, { vendor: string; usage: 'build' | 'deployment' }>();
614
+ for (const [vendor, facts] of Object.entries(packFacts())) {
615
+ for (const tool of facts.adoption?.tools ?? []) tools.set(tool.package, { vendor, usage: tool.usage });
616
+ }
617
+ for (const dependency of dependencies) {
618
+ const tool = tools.get(dependency);
619
+ if (tool !== undefined) {
620
+ mappedDeps.add(dependency);
621
+ detected.set(tool.vendor, [...(detected.get(tool.vendor) ?? []), `${tool.usage}-tool: npm: ${dependency}`]);
622
+ continue;
623
+ }
624
+ // `pypi:<name>` is the Python half (project-inspect's PYPI_TWINS, descriptors' adoption.pypi).
625
+ const py = dependency.startsWith('pypi:') ? dependency.slice(5) : undefined;
626
+ const vendor = py !== undefined ? PYPI_TWINS[py]?.vendor : (SDK_TWINS[dependency]?.vendor ?? scopeVendorFor(dependency));
627
+ if (vendor === undefined) continue;
628
+ mappedDeps.add(dependency);
629
+ detected.set(vendor, [...(detected.get(vendor) ?? []), py !== undefined ? `pypi: ${py}` : `npm: ${dependency}`]);
630
+ }
631
+ for (const name of envNames) {
632
+ if (/_TWIN_URL$/.test(name) || /^VOLTER_/.test(name)) continue;
633
+ // The raw-protocol mail path. This used to fall through to `unknown` because no SMTP twin
634
+ // existed, which was the honest answer THEN; the `smtp` pack now twins it, so the same signal
635
+ // is a DETECTED vendor and a world carrying an smtp service covers it. (The env NAME is the
636
+ // whole interception story here — there is no host for the injector to rewrite, so
637
+ // SMTP_HOST/EMAIL_SERVER_HOST pointed at the twin's listener is what redirects the app.)
638
+ if (isSmtpEnvSignal(name)) {
639
+ // NB this sits BEFORE the stem lookup, so a vendor-NAMED mail host (`POSTMARK_SMTP_HOST`,
640
+ // `MAILGUN_SMTP_HOST`) attributes to the `smtp` twin rather than to that vendor's HTTP pack.
641
+ // Deliberate: the var names an SMTP endpoint, and pointing it at the twin's listener is what
642
+ // actually redirects the mail — postmark's REST twin would not receive it.
643
+ detected.set('smtp', [...(detected.get('smtp') ?? []), `env: ${name}`]);
644
+ continue;
645
+ }
646
+ const stem = envVendorStem(name, ENV_SUFFIX_BROAD);
647
+ const vendor = stem === null ? undefined : ENV_STEM_VENDORS[stem];
648
+ if (vendor) detected.set(vendor, [...(detected.get(vendor) ?? []), `env: ${name}`]);
649
+ }
650
+
651
+ // The npm registry injector deliberately owns only npmjs.org and GitHub Packages. A custom
652
+ // configured registry is a distinct uncovered destination even when NPM_TOKEN also detects the
653
+ // official npm twin; treating the credential as coverage would silently send private-registry
654
+ // traffic to the real network.
655
+ const officialNpmHosts = new Set(['registry.npmjs.org', 'npm.pkg.github.com']);
656
+ for (const registry of npmRegistries) {
657
+ const hostname = new URL(registry.url).hostname.toLowerCase();
658
+ if (officialNpmHosts.has(hostname)) {
659
+ detected.set('npm-registry', [...(detected.get('npm-registry') ?? []), `registry: ${registry.source} -> ${hostname}`]);
660
+ }
661
+ }
662
+
663
+ // Raw-fetch vendor discovery. A hand-written client has no SDK dependency, and its credential
664
+ // may use a project-specific name; the literal destination is the one unambiguous signal left.
665
+ // Match it through the injector's OWN predicates, including pathname-aware shared hosts.
666
+ const knownVendorById = new Map<string, string>();
667
+ for (const vendor of [
668
+ ...Object.values(SDK_TWINS).map((entry) => entry.vendor),
669
+ ...Object.values(ENV_STEM_VENDORS),
670
+ ...Object.keys(VENDOR_WORLD_IDS),
671
+ ]) knownVendorById.set(normalizeId(vendor), vendor);
672
+ const canonicalVendor = (injectorKey: string): string | null => {
673
+ const key = normalizeId(injectorKey);
674
+ for (const [vendor, ids] of Object.entries(VENDOR_WORLD_IDS)) {
675
+ if (ids.includes(key)) return vendor;
676
+ }
677
+ return knownVendorById.get(key) ?? null;
678
+ };
679
+ const vendorHosts = loadInject().VENDOR_HOSTS;
680
+ for (const signal of projectFetchUrls(repo)) {
681
+ const url = new URL(signal.url);
682
+ const vendors = new Set<string>();
683
+ for (const [injectorKey, matches] of Object.entries(vendorHosts)) {
684
+ if (!matches(url.hostname, url.pathname)) continue;
685
+ const vendor = canonicalVendor(injectorKey);
686
+ if (vendor !== null) vendors.add(vendor);
687
+ }
688
+ for (const vendor of [...vendors].sort()) {
689
+ const source = `fetch: ${signal.source} -> ${url.hostname}`;
690
+ detected.set(vendor, [...(detected.get(vendor) ?? []), source]);
691
+ }
692
+ }
693
+
694
+ // unknown external-service-shaped signals (no vendor mapping). A dep from a scope with a
695
+ // twin-mapped sibling counts even when its own name is not service-shaped — the Dub run's
696
+ // @upstash/redis + @upstash/ratelimit disappeared exactly here while @upstash/qstash mapped.
697
+ const unknown = new Map<string, string[]>();
698
+ for (const registry of npmRegistries) {
699
+ const hostname = new URL(registry.url).hostname.toLowerCase();
700
+ if (officialNpmHosts.has(hostname)) continue;
701
+ const id = `npm-registry@${hostname}`;
702
+ unknown.set(id, [...(unknown.get(id) ?? []), `registry: ${registry.source} -> ${hostname}`]);
703
+ }
704
+ for (const dependency of dependencies) {
705
+ if (mappedDeps.has(dependency)) continue;
706
+ if (isExternalServiceShapedDep(dependency) || isMappedScopeSibling(dependency)) {
707
+ unknown.set(dependency, [...(unknown.get(dependency) ?? []), `npm: ${dependency}`]);
708
+ }
709
+ }
710
+ for (const name of envNames) {
711
+ if (/_TWIN_URL$/.test(name) || /^VOLTER_/.test(name)) continue;
712
+ if (isSmtpEnvSignal(name)) continue; // now a DETECTED vendor (above), no longer an unknown
713
+ const stem = envVendorStem(name, ENV_SUFFIX_STRICT);
714
+ if (stem === null || ENV_STEM_VENDORS[stem] || ENV_STEM_IGNORE.has(stem)) continue;
715
+ // The registry's notExternal suppressions apply to ENV STEMS too — the census adjudicated
716
+ // 40 app-internal stems ("names no vendor") that this loop kept flagging because only the
717
+ // dep-side checks consulted the registry (§9 round two H4, 2026-08-31: 17 of 18 formally
718
+ // dead stems still failed the proof).
719
+ if (knownExternalServices().notExternal[stem] !== undefined) continue;
720
+ unknown.set(stem, [...(unknown.get(stem) ?? []), `env: ${name}`]);
721
+ }
722
+ return { detected, unknown, uses: usesOf(detected), unknownUses: usesOf(unknown) };
723
+ }
724
+
725
+ export function coverWorld(world: string, repoPath: string, options: CoverageOptions = {}): CoverageReport {
726
+ const root = resolve(options.root ?? process.cwd());
727
+ const allowUnknown = options.allowUnknown ?? false;
728
+ const acknowledge = options.acknowledge ?? {};
729
+ for (const [vendor, reason] of Object.entries(acknowledge)) {
730
+ if (!reason.trim()) throw new Error(`covers: --acknowledge ${vendor} requires a non-empty reason (vendor=reason)`);
731
+ }
732
+ const repo = resolve(repoPath);
733
+ const inventory = worldTwinInventory(world, root);
734
+
735
+ const { detected, unknown: unknownSources, uses, unknownUses } = detectRepoVendors(repo);
736
+
737
+ // Does ANY injector vendor key exist for this vendor? Decides whether an UNINTERCEPTABLE
738
+ // finding is acknowledgeable: a key that exists means the twin COULD be intercepted and the
739
+ // wiring is merely wrong (fix it, don't acknowledge it); no key at all means the pack is a
740
+ // stated vendor-hosts allowlist gap (explicit-endpoint wiring only) and a world that still
741
+ // declares the twin may honestly acknowledge the finding rather than delete the twin.
742
+ const injectorKeysFor = injectorVendorKeysFor;
743
+
744
+ const rows: CoverageRow[] = [];
745
+ const covered: string[] = [];
746
+ const acknowledged: { vendor: string; reason: string }[] = [];
747
+ const missing: string[] = [];
748
+ const uninterceptable: string[] = [];
749
+ const excluded: string[] = [];
750
+ for (const [vendor, sources] of [...detected.entries()].sort(([a], [b]) => a.localeCompare(b))) {
751
+ const selected = inventory.selection === undefined || (uses.get(vendor) ?? []).some((use) => worldSelectionIncludes(inventory.selection!, vendor, use.usage));
752
+ if (!selected) {
753
+ excluded.push(vendor);
754
+ rows.push({ vendor, detectedVia: sources, twinInWorld: null, status: 'excluded' });
755
+ continue;
756
+ }
757
+ // a vendor is only COVERED by a twin traffic can actually reach; a present-but-unreachable
758
+ // twin (no injector vendor, no app-read endpoint env) is a distinct, failing status.
759
+ const candidates = worldIdsFor(vendor).filter((id) => inventory.ids.has(id));
760
+ const matchId = candidates.find((id) => inventory.ids.get(id)!.interceptable) ?? candidates[0];
761
+ const match = matchId === undefined ? null : inventory.ids.get(matchId)!;
762
+ let status: CoverageStatus = match === null ? 'missing' : match.interceptable ? 'covered' : 'uninterceptable';
763
+ let ackRefused: string | undefined;
764
+ if (acknowledge[vendor] !== undefined) {
765
+ if (status === 'missing') status = 'acknowledged';
766
+ else if (status === 'uninterceptable') {
767
+ const keys = injectorKeysFor(vendor);
768
+ if (keys.length === 0) status = 'acknowledged';
769
+ else {
770
+ ackRefused =
771
+ `acknowledge REFUSED: injector key(s) ${keys.join('/')} exist for this vendor — the twin CAN be intercepted, ` +
772
+ `the wiring is merely wrong. Fix it (${keys.map(injectorEnvNameForKey).join(' / ')}) instead of acknowledging`;
773
+ }
774
+ }
775
+ }
776
+ if (status === 'covered') covered.push(vendor);
777
+ else if (status === 'missing') missing.push(vendor);
778
+ else if (status === 'acknowledged') acknowledged.push({ vendor, reason: acknowledge[vendor]! });
779
+ else uninterceptable.push(vendor);
780
+ rows.push({
781
+ vendor,
782
+ ...(packFacts()[vendor]?.transport ? { connection: packFacts()[vendor]!.transport } : {}),
783
+ detectedVia:
784
+ status === 'acknowledged'
785
+ ? [...sources, `acknowledged: ${acknowledge[vendor]}`]
786
+ : ackRefused !== undefined
787
+ ? [...sources, ackRefused]
788
+ : sources,
789
+ twinInWorld: match === null ? null : match.label,
790
+ status,
791
+ });
792
+ }
793
+ const unknown: string[] = [];
794
+ for (const [name, sources] of [...unknownSources.entries()].sort(([a], [b]) => a.localeCompare(b))) {
795
+ const selected = inventory.selection === undefined || (unknownUses.get(name) ?? []).some((use) => worldSelectionIncludes(inventory.selection!, name, use.usage));
796
+ if (!selected) {
797
+ excluded.push(name);
798
+ rows.push({ vendor: name, detectedVia: sources, twinInWorld: null, status: 'excluded' });
799
+ continue;
800
+ }
801
+ if (acknowledge[name] !== undefined) {
802
+ acknowledged.push({ vendor: name, reason: acknowledge[name]! });
803
+ rows.push({ vendor: name, detectedVia: [...sources, `acknowledged: ${acknowledge[name]}`], twinInWorld: null, status: 'acknowledged' });
804
+ continue;
805
+ }
806
+ // STANDING acknowledgments from the packless-vendor registry: a signal the census rulings
807
+ // adjudicated acceptable (config-time adapters, per-repo-judged surfaces) acknowledges
808
+ // itself with the RECORDED reason — the same status a per-run `--acknowledge` grants, but
809
+ // sourced from committed adjudication instead of a flag. Demanded registry entries fall
810
+ // through to unknown-sdk on purpose: known-but-packless is still an uncovered vendor.
811
+ const standing = registryAcknowledgedReason(name);
812
+ if (standing !== null) {
813
+ acknowledged.push({ vendor: name, reason: standing });
814
+ rows.push({ vendor: name, detectedVia: [...sources, `acknowledged (registry): ${standing}`], twinInWorld: null, status: 'acknowledged' });
815
+ continue;
816
+ }
817
+ unknown.push(name);
818
+ rows.push({ vendor: name, detectedVia: sources, twinInWorld: null, status: 'unknown-sdk' });
819
+ }
820
+
821
+ for (const [vendor, declared] of [...inventory.declared].sort(([a], [b]) => a.localeCompare(b))) {
822
+ // Selection can exclude a detected use from automatic coverage obligations, but it cannot
823
+ // hide broken routing for a service the operator explicitly declared. Keep the excluded row
824
+ // and add the declaration's independent routing verdict.
825
+ if (rows.some((row) => row.vendor === vendor && row.status !== 'excluded')) continue;
826
+ const status: CoverageStatus = declared.interceptable ? 'covered' : 'uninterceptable';
827
+ if (status === 'covered') covered.push(vendor); else uninterceptable.push(vendor);
828
+ rows.push({ vendor, detectedVia: ['declared in world'], twinInWorld: declared.label, status });
829
+ }
830
+
831
+ for (const requirement of projectConnections(repo, new Set(
832
+ [...detected.values(), ...unknownSources.values()].flat().filter((source) => source.startsWith('env: ')).map((source) => source.slice(5)),
833
+ ))) {
834
+ const vendor = `${requirement.protocol ?? 'unknown-connection'}:${requirement.env ?? requirement.sources[0]}`;
835
+ if (inventory.selection !== undefined && !worldSelectionIncludes(inventory.selection, vendor, 'application')) {
836
+ excluded.push(vendor);
837
+ rows.push({
838
+ vendor,
839
+ connection: requirement.protocol ?? 'unknown',
840
+ detectedVia: requirement.sources,
841
+ twinInWorld: null,
842
+ status: 'excluded',
843
+ });
844
+ continue;
845
+ }
846
+ const binding = requirement.env === undefined ? undefined : inventory.connections.get(requirement.env);
847
+ // An HTTP-valued endpoint variable the world injects from a twin (its endpoint env or a
848
+ // template) is routed to that twin; only an HTTP URL nobody in the world supplies stays unknown.
849
+ const injectedHttp = requirement.protocol === null && binding?.protocol === 'http';
850
+ const unresolved = !injectedHttp && (requirement.protocol === null || requirement.env === undefined || (binding !== undefined && binding.protocol === null));
851
+ let status: CoverageStatus = unresolved ? 'unknown-sdk'
852
+ : injectedHttp || binding?.protocol === requirement.protocol ? 'covered' : 'missing';
853
+ if (status !== 'covered' && acknowledge[vendor] !== undefined) {
854
+ status = 'acknowledged';
855
+ acknowledged.push({ vendor, reason: acknowledge[vendor]! });
856
+ } else if (status === 'covered') covered.push(vendor);
857
+ else if (status === 'missing') missing.push(vendor);
858
+ else unknown.push(vendor);
859
+ rows.push({
860
+ vendor,
861
+ connection: requirement.protocol ?? 'unknown',
862
+ detectedVia: [...requirement.sources, ...(status === 'acknowledged' ? [`acknowledged: ${acknowledge[vendor]}`] : [])],
863
+ twinInWorld: binding?.label ?? null,
864
+ status,
865
+ });
866
+ }
867
+
868
+ return {
869
+ world,
870
+ worldSource: inventory.source,
871
+ worldPath: inventory.path,
872
+ repo,
873
+ twinsInWorld: [...inventory.ids.values()].map((id) => id.label).sort(),
874
+ rows,
875
+ covered,
876
+ missing,
877
+ uninterceptable,
878
+ unknown,
879
+ acknowledged,
880
+ excluded,
881
+ allowUnknown,
882
+ ok: missing.length === 0 && uninterceptable.length === 0 && (allowUnknown || unknown.length === 0),
883
+ };
884
+ }
885
+
886
+ export function formatCoverageReport(report: CoverageReport): string {
887
+ const lines: string[] = [];
888
+ lines.push(`World ${report.world} (${report.worldSource}: ${report.worldPath})`);
889
+ lines.push(`Repo ${report.repo}`);
890
+ lines.push('');
891
+ const header = ['vendor / connection', 'transport', 'detected-via', 'twin-in-world', 'status'];
892
+ const cells = report.rows.map((row) => [
893
+ row.vendor,
894
+ row.connection ?? '-',
895
+ row.detectedVia.join('; '),
896
+ row.twinInWorld ?? '-',
897
+ row.status === 'missing' ? 'MISSING' : row.status === 'uninterceptable' ? 'UNINTERCEPTABLE' : row.status,
898
+ ]);
899
+ const widths = header.map((title, column) => Math.max(title.length, ...cells.map((row) => row[column]!.length)));
900
+ const renderRow = (row: string[]): string => row.map((cell, column) => cell.padEnd(widths[column]!)).join(' | ').trimEnd();
901
+ lines.push(renderRow(header));
902
+ lines.push(widths.map((width) => '-'.repeat(width)).join('-|-'));
903
+ for (const row of cells) lines.push(renderRow(row));
904
+ if (report.rows.length === 0) lines.push('(no external vendor dependencies detected in the repo)');
905
+ lines.push('');
906
+ if (report.missing.length > 0) {
907
+ lines.push(`NOT COVERED: ${report.missing.length} vendor(s) with no twin in world ${report.world}: ${report.missing.join(', ')}`);
908
+ lines.push(` add the missing twin service(s) to the world config, then re-run the proof.`);
909
+ }
910
+ if (report.uninterceptable.length > 0) {
911
+ lines.push(`UNINTERCEPTABLE: ${report.uninterceptable.length} vendor(s) have a twin in world ${report.world} that no traffic can reach: ${report.uninterceptable.join(', ')}`);
912
+ lines.push(` the twin is present, but its service resolves to no injector vendor (VENDOR_HOSTS in @volter/world-core/inject) and exposes no app-read endpoint env — SDK calls would go to the REAL vendor. Use the injector's vendor keys for injectEnv (e.g. S3_TWIN_URL, not AWS_TWIN_URL) or wire explicit endpoint env, then re-run the proof. If NO injector key exists for the vendor at all (a stated vendor-hosts allowlist gap), --acknowledge vendor=reason is accepted; when a key exists, acknowledgment is refused — fix the wiring.`);
913
+ }
914
+ if (report.unknown.length > 0) {
915
+ const verdict = report.allowUnknown ? 'WARNING (allowed by --allow-unknown)' : 'UNKNOWN-SDK: fails the proof';
916
+ lines.push(`${verdict}: ${report.unknown.length} external-service-shaped signal(s) with unresolved SDK/connection mapping: ${report.unknown.join(', ')}`);
917
+ if (!report.allowUnknown) lines.push(' resolve the reported SDK/connection and its endpoint wiring; boot the World to resolve external.discover bindings. --allow-unknown explicitly accepts remaining unknowns.');
918
+ }
919
+ // Acknowledgments are part of the verdict, not fine print: a proof that passed WITH
920
+ // acknowledged rows must say so (and how many were standing/registry vs per-run flags) —
921
+ // "COVERED" alone would overstate a world whose acknowledged vendors have no twin at all
922
+ // (§9 round two M1, 2026-08-31: CoverageReport.acknowledged had no production consumer).
923
+ if (report.acknowledged.length > 0) {
924
+ lines.push(`ACKNOWLEDGED: ${report.acknowledged.length} signal(s) accepted with recorded reasons (no twin): ${report.acknowledged.map((a) => a.vendor).join(', ')}`);
925
+ }
926
+ if (report.excluded.length > 0) lines.push(`EXCLUDED BY SELECTION: ${report.excluded.join(', ')} (not covered; no access granted).`);
927
+ lines.push(report.ok
928
+ ? report.acknowledged.length > 0
929
+ ? `COVERED (with ${report.acknowledged.length} acknowledgment(s)): every other detected vendor has a twin in world ${report.world}.`
930
+ : `COVERED: every detected vendor has a twin in world ${report.world}.`
931
+ : `PROOF FAILED for world ${report.world}.`);
932
+ lines.push('Static connection check only; run an app scenario to verify behavior and shared state.');
933
+ return `${lines.join('\n')}\n`;
934
+ }