@volter/twin-world 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/covers.ts ADDED
@@ -0,0 +1,724 @@
1
+ // `volter-world covers <world> --repo <path>` — the room-setup COVERAGE PROOF (the twin
2
+ // half of the "room ensure params" doctrine): prove that every external vendor an
3
+ // application repo talks to has a twin IN the named world, so an agent working in that
4
+ // room can never silently reach a real vendor the world forgot to twin.
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 { projectDependencies, projectEnvNames, projectFetchUrls, projectNpmRegistries, PYPI_TWINS, SDK_TWINS } from './project-inspect.ts';
31
+ import { overlayCoversMaps } from './pack-facts.ts';
32
+ import { statusWorld } from './runtime.ts';
33
+ import type { WorldServiceConfig } from './schema.ts';
34
+
35
+ export type CoverageStatus = 'covered' | 'missing' | 'uninterceptable' | 'unknown-sdk' | 'acknowledged';
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
+ /** the matching world service/env identifier when covered, else null */
43
+ twinInWorld: string | null;
44
+ status: CoverageStatus;
45
+ };
46
+
47
+ export type CoverageReport = {
48
+ world: string;
49
+ /** 'instance' when a booted/recorded instance was read; 'config' for the stable config */
50
+ worldSource: 'instance' | 'config';
51
+ worldPath: string;
52
+ repo: string;
53
+ twinsInWorld: string[];
54
+ rows: CoverageRow[];
55
+ covered: string[];
56
+ missing: string[];
57
+ /** vendors whose twin IS in the world but nothing can route vendor traffic to it (the
58
+ * service resolves to no injector vendor and exposes no app-read endpoint env) — the
59
+ * LibreChat AWS_TWIN_URL trap. Fails the proof: a twin nothing reaches covers nothing. */
60
+ uninterceptable: string[];
61
+ unknown: string[];
62
+ acknowledged: { vendor: string; reason: string }[];
63
+ allowUnknown: boolean;
64
+ ok: boolean;
65
+ };
66
+
67
+ /** identifiers are compared case/punctuation-insensitively: 's3', 'S3_TWIN_URL' stem,
68
+ * a 'stripe' service id and the 'ai-gateway' pack name all normalize cleanly. */
69
+ function normalizeId(text: string): string {
70
+ return text.toLowerCase().replace(/[^a-z0-9]/g, '');
71
+ }
72
+
73
+ /** Which world-side identifiers (normalized service ids / *_TWIN_URL stems / pack names)
74
+ * count as covering a vendor. Default: the vendor key itself. Extras cover the packs whose
75
+ * world identity differs from the SDK vendor key (the consolidated aws twin answers as
76
+ * s3/dynamodb/timestream; cookbook supabase worlds inject SUPABASE_MGMT_TWIN_URL). */
77
+ const VENDOR_WORLD_IDS: Record<string, string[]> = {
78
+ // (empty — every entry has moved onto its pack descriptor. See the note below.)
79
+ };
80
+
81
+ function worldIdsFor(vendor: string): string[] {
82
+ return VENDOR_WORLD_IDS[vendor] ?? [normalizeId(vendor)];
83
+ }
84
+
85
+ /**
86
+ * The INJECTOR vendor keys that can carry this vendor's traffic, in a stable order — the single
87
+ * source of truth for "can zero-edit interception work here, and under which `*_TWIN_URL` name?".
88
+ *
89
+ * Read from `@volter/twin/inject`'s own VENDOR_HOSTS table (never a re-encoding of it), and
90
+ * filtered through the same `VENDOR_WORLD_IDS` aliasing the proof matches with: `aws` yields
91
+ * `['s3','dynamodb','timestream']` (the consolidated twin's real keys — `AWS_TWIN_URL` is the
92
+ * inert trap), `stripe` yields `['stripe']`, and a pack in vendor-hosts.test.ts's
93
+ * descriptor hostsNone ruling yields `[]`.
94
+ *
95
+ * Two callers, one answer: `covers` uses it to decide whether an UNINTERCEPTABLE finding is a
96
+ * fixable wiring bug (keys exist) or an acknowledgeable allowlist gap (none do), and `init` uses
97
+ * it to DERIVE the canonical `injectEnv` it emits — so an emitted world can never claim a
98
+ * `*_TWIN_URL` var the injector does not read.
99
+ */
100
+ export function injectorVendorKeysFor(vendor: string): string[] {
101
+ const worldIds = new Set(worldIdsFor(vendor));
102
+ return [...injectableVendorKeys()].filter((key) => worldIds.has(normalizeId(key)));
103
+ }
104
+
105
+ /** Shell-safe env name read by the injector for a vendor key, including hyphenated keys. */
106
+ export function injectorEnvNameForKey(key: string): string {
107
+ return `${key.toUpperCase().replace(/[^A-Z0-9]/g, '_')}_TWIN_URL`;
108
+ }
109
+
110
+ /** Vendor-shaped env var detection (the secondary signal). The var must end in a
111
+ * credential/endpoint suffix; the remaining stem (framework prefixes stripped,
112
+ * normalized) is looked up here. */
113
+ // Exported for scripts/packless-claims.test.ts, which checks the packless registry against
114
+ // the OVERLAID map (legacy entries + descriptor adoption.envStems in one view) — importing
115
+ // the real map is unbreakable by formatting, unlike the source-parsing it replaced (§9
116
+ // skeptic M3, 2026-08-31: a reflow or quote-style change silently emptied the parsed set).
117
+ export const ENV_STEM_VENDORS: Record<string, string> = {
118
+ // (empty — every entry has moved onto its pack descriptor. See the note below.)
119
+ };
120
+
121
+ const ENV_FRAMEWORK_PREFIX = /^(NEXT_PUBLIC_|VITE_|REACT_APP_|EXPO_PUBLIC_|NUXT_PUBLIC_|PUBLIC_)/;
122
+
123
+ /** Broad credential/endpoint suffixes — used to derive a stem for KNOWN-vendor detection
124
+ * (a false stem is harmless: it only counts when the stem hits ENV_STEM_VENDORS). */
125
+ const ENV_SUFFIX_BROAD =
126
+ /_(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)$/;
127
+
128
+ /** Narrow, unmistakably vendor-shaped suffixes — a var with one of these whose stem maps
129
+ * to NO known vendor is an unknown external service and fails the proof. (Deliberately
130
+ * excludes bare _SECRET/_TOKEN/_KEY: JWT_SECRET / SESSION_SECRET are app-local. _REST_URL
131
+ * is here on purpose: it is a hosted-service endpoint shape — UPSTASH_REDIS_REST_URL
132
+ * produced NO row at all in the Dub blind-adoption run. _CLIENT_ID/_CLIENT_SECRET/
133
+ * _CONSUMER_KEY are here on purpose too: they are the OAuth-app credential shape, and
134
+ * before they were strict the Cal.com blind run silently dropped NINE OAuth vendors —
135
+ * ZOOM_CLIENT_ID, MS_GRAPH_CLIENT_SECRET, SALESFORCE_CONSUMER_KEY, GOOGLE_CLIENT_ID, … —
136
+ * from a proof that exited 0. The env-detection heuristic was structurally biased against
137
+ * exactly the vendor class integration-heavy apps are made of.) */
138
+ const ENV_SUFFIX_STRICT = /_(API_KEY|APIKEY|API_TOKEN|API_SECRET|OAUTH_TOKEN|CLIENT_ID|CLIENT_SECRET|CONSUMER_KEY|ACCOUNT_SID|DSN|REST_URL)$/;
139
+
140
+ /** App-local stems that must never be flagged as an unknown vendor. `redis` is deliberately
141
+ * NOT here: a redis-stemmed var only reaches this lookup through a vendor-shaped suffix
142
+ * (e.g. REDIS_REST_URL — hosted Redis, an external service), while plain local-Redis vars
143
+ * (REDIS_URL, REDIS_HOST, REDIS_PASSWORD) never match ENV_SUFFIX_STRICT in the first place. */
144
+ const ENV_STEM_IGNORE = new Set([
145
+ 'jwt', 'session', 'auth', 'nextauth', 'app', 'api', 'admin', 'internal', 'server', 'client',
146
+ 'cookie', 'csrf', 'encryption', 'webhook', 'test', 'dev', 'local', 'demo', 'example', 'my',
147
+ 'database', 'db', 'postgres', 'mysql', 'mongo', 'smtp', 'volter', 'twin', 'world',
148
+ // generic IdP-config stems: OAUTH_CLIENT_ID / OIDC_CLIENT_SECRET name a PROTOCOL role, not a
149
+ // vendor — now that _CLIENT_ID/_CLIENT_SECRET are strict suffixes these would otherwise raise
150
+ // a false unknown-vendor alarm on every app with a generic OAuth config block. Vendor-named
151
+ // stems (ZOOM_, SALESFORCE_, GOOGLE_, …) still surface.
152
+ 'oauth', 'oidc',
153
+ ]);
154
+
155
+ function envVendorStem(name: string, suffix: RegExp): string | null {
156
+ const stripped = name.replace(ENV_FRAMEWORK_PREFIX, '');
157
+ const match = stripped.match(suffix);
158
+ if (!match || match.index === undefined || match.index === 0) return null;
159
+ return normalizeId(stripped.slice(0, match.index));
160
+ }
161
+
162
+ /** Is this env NAME shaped like a CREDENTIAL/endpoint at all (any broad vendor suffix)? The
163
+ * question `init` asks before deciding whether a value in a repo's `.env.example` may be copied
164
+ * verbatim: `APP_NAME` may, `ANYTHING_SECRET` may not — a committed example file is exactly where
165
+ * live keys hide (the ponder blind-adoption run found real ones), so a credential-shaped name is
166
+ * ALWAYS replaced by a fake, whether or not its stem maps to a vendor this repo twins. Exported
167
+ * from here so the emission path and the proof read ONE definition of "credential-shaped". */
168
+ export function isCredentialShapedEnvName(name: string): boolean {
169
+ return ENV_SUFFIX_BROAD.test(name.replace(ENV_FRAMEWORK_PREFIX, ''));
170
+ }
171
+
172
+ /** The vendor a credential-shaped env NAME betrays, or null. Same broad-suffix route the
173
+ * coverage proof's secondary signal uses (`STRIPE_SECRET_KEY` → 'stripe'). */
174
+ export function envNameVendor(name: string): string | null {
175
+ // ⚠️ This deliberately does NOT claim the SMTP host/URL vars, even though `detectRepoVendors`
176
+ // below detects them as vendor `smtp`. The two functions answer DIFFERENT questions, and §9
177
+ // found both halves of that the hard way:
178
+ // • round 1 called the divergence an inconsistency ("one answer per name");
179
+ // • round 2 showed what happens when you remove it. This function's only caller is `init`'s
180
+ // env emission (`init.ts`), which REPLACES a credential-shaped value with `twin-fake-<name>`.
181
+ // Claiming `SMTP_URL`/`EMAIL_SERVER` here turned NextAuth's `smtp://user:pass@host:port` into
182
+ // `twin-fake-email-server`, which `new URL(...)` cannot parse — breaking the app to protect a
183
+ // value that was never a credential in the first place.
184
+ // So: this asks "is this name a VENDOR CREDENTIAL that must be faked?" (a hostname is not), while
185
+ // `detectRepoVendors` asks "which vendors does this repo talk to?" (the mail path certainly is
186
+ // one). Same string, two honest answers.
187
+ const stem = envVendorStem(name, ENV_SUFFIX_BROAD);
188
+ return stem === null ? null : ENV_STEM_VENDORS[stem] ?? null;
189
+ }
190
+
191
+ /** SMTP-shaped env names — the raw-protocol mail path (nodemailer et al.) the HTTP-vendor
192
+ * heuristics above are structurally blind to. The Cal.com blind run's booking-confirmation
193
+ * mail (EMAIL_SERVER_HOST/EMAIL_SERVER_PORT) was invisible to the proof while being the
194
+ * single most important vendor touchpoint of the app. Conservative stem+suffix approach:
195
+ * only the HOST/URL forms count (`SMTP_HOST`, `MAILGUN_SMTP_HOST`, `SMTP_URL`, and
196
+ * NextAuth/nodemailer's `EMAIL_SERVER`/`EMAIL_SERVER_HOST` connection forms) — a bare
197
+ * SMTP_USER/_PASSWORD without a host proves nothing and would duplicate rows.
198
+ *
199
+ * This signal used to surface as unknown-sdk ('smtp') because no SMTP twin existed — the honest
200
+ * outcome at the time. The `smtp` pack now twins the protocol, so it is a DETECTED vendor and a
201
+ * world that runs an smtp service covers it. What has NOT changed is why the signal has to be a
202
+ * dedicated route at all: SMTP is intercepted through the app-read env name itself, not through a
203
+ * host the injector rewrites, so the env var IS the touchpoint rather than a hint about one.
204
+ * (The 'smtp' entry in ENV_STEM_IGNORE guards the generic-suffix stem route; this signal is
205
+ * deliberate and separate.) */
206
+ function isSmtpEnvSignal(name: string): boolean {
207
+ const stripped = name.replace(ENV_FRAMEWORK_PREFIX, '');
208
+ return /(^|_)SMTP_(HOST|URL)$/.test(stripped) || /^EMAIL_SERVER(_HOST)?$/.test(stripped);
209
+ }
210
+
211
+ /** npm scopes whose EVERY package is one vendor's client surface — an unmapped
212
+ * satellite package (`@sentry/cli`, `@datadog/browser-logs`, `@octokit/graphql`)
213
+ * still detects (and is covered by) that vendor's twin. Deliberately NOT `@aws-sdk`
214
+ * or `@azure`/`@google-cloud`: those scopes span many services and the consolidated
215
+ * twins only model some of them — unmapped clients there must stay unknown-sdk. */
216
+ const SDK_SCOPE_VENDORS: Record<string, string> = {
217
+ // (empty — every entry has moved onto its pack descriptor. See the note below.)
218
+ };
219
+ // TWIN-PACK-CONTRACT migration, COMPLETE for these three tables: every pack declares its own
220
+ // scopes / env stems / world ids (`adoption` on its descriptor, compiled into the committed
221
+ // pack-facts artifact), and all three literals above are now empty — they are populated entirely
222
+ // by the overlay below. They are kept as the overlay's targets, not as homes: the object identity
223
+ // is what every use site already reads, so nothing downstream changed. Do NOT re-add an entry
224
+ // here; a fact declared in both homes throws at module init.
225
+ overlayCoversMaps({ scopeVendors: SDK_SCOPE_VENDORS, envStemVendors: ENV_STEM_VENDORS, vendorWorldIds: VENDOR_WORLD_IDS });
226
+
227
+ export function scopeVendorFor(name: string): string | undefined {
228
+ const entry = Object.entries(SDK_SCOPE_VENDORS).find(([prefix]) => name === prefix || name.startsWith(prefix));
229
+ return entry?.[1];
230
+ }
231
+
232
+ /** npm scopes holding at least one twin-mapped package (from SDK_TWINS' scoped keys and
233
+ * SDK_SCOPE_VENDORS). An UNMAPPED sibling from such a scope is almost always another external
234
+ * surface of the same platform — in the Dub blind-adoption run, `@upstash/redis` and
235
+ * `@upstash/ratelimit` produced NO row at all while `@upstash/qstash` was mapped, a silent
236
+ * blind spot. Such siblings surface as unknown-sdk instead of disappearing. */
237
+ const MAPPED_SCOPES: ReadonlySet<string> = new Set(
238
+ [...Object.keys(SDK_TWINS), ...Object.keys(SDK_SCOPE_VENDORS)]
239
+ .filter((name) => name.startsWith('@'))
240
+ .map((name) => `${name.split('/')[0]}/`),
241
+ );
242
+
243
+ export function isMappedScopeSibling(name: string): boolean {
244
+ if (knownExternalServices().notExternal[name] !== undefined) return false;
245
+ return [...MAPPED_SCOPES].some((scope) => name.startsWith(scope));
246
+ }
247
+
248
+ /**
249
+ * THE PACKLESS-VENDOR REGISTRY — `known-external-services.json`, shipped inside this package.
250
+ * ONE home for the knowledge that used to live in three inline sets here (NOT_AN_EXTERNAL_
251
+ * SERVICE, UNKNOWN_DEP_KNOWN_SERVICES, UNKNOWN_DEP_PATTERNS) plus the 2026-08-31 census
252
+ * rulings: `deps`/`envStems` are external-service signals the catalog KNOWS but has no pack
253
+ * for (`disposition: 'demanded'` stays a LOUD coverage gap — the demand queue;
254
+ * `'acknowledged'` was adjudicated acceptable and auto-acknowledges with its recorded
255
+ * reason); `notExternal` suppresses vendor-adjacent glue (protocol/type/UI helpers, auth
256
+ * libraries); `patterns` are the external-shape heuristics. AN ENTRY DIES THE DAY ITS PACK
257
+ * IS BORN — scripts/packless-claims.test.ts enforces disjointness with pack adoption and
258
+ * SDK_TWINS (the `@planetscale/database`/twin#255 lesson, mechanized). Lazy + cached like
259
+ * pack-facts.ts's loader — though note this module ALREADY does module-scope I/O via the
260
+ * overlayCoversMaps call below, so laziness here is consistency, not a load-bearing
261
+ * invariant (§9 round two L1).
262
+ */
263
+ export type PacklessDisposition = 'demanded' | 'acknowledged';
264
+ export type PacklessEntry = { disposition: PacklessDisposition; reason: string };
265
+ export type KnownExternalServices = {
266
+ deps: Record<string, PacklessEntry>;
267
+ envStems: Record<string, PacklessEntry>;
268
+ notExternal: Record<string, string>;
269
+ patterns: Array<{ pattern: string; reason: string }>;
270
+ };
271
+
272
+ let registryCache: KnownExternalServices | undefined;
273
+ export function knownExternalServices(): KnownExternalServices {
274
+ if (registryCache === undefined) {
275
+ const path = join(dirname(fileURLToPath(import.meta.url)), '..', 'known-external-services.json');
276
+ registryCache = JSON.parse(readFileSync(path, 'utf8')) as KnownExternalServices;
277
+ }
278
+ return registryCache;
279
+ }
280
+
281
+ let patternCache: RegExp[] | undefined;
282
+ function unknownDepPatterns(): RegExp[] {
283
+ patternCache ??= knownExternalServices().patterns.map((p) => new RegExp(p.pattern));
284
+ return patternCache;
285
+ }
286
+
287
+ function isExternalServiceShapedDep(name: string): boolean {
288
+ const registry = knownExternalServices();
289
+ if (registry.notExternal[name] !== undefined) return false;
290
+ if (registry.deps[name] !== undefined) return true;
291
+ return unknownDepPatterns().some((pattern) => pattern.test(name));
292
+ }
293
+
294
+ /** The registry's STANDING acknowledgment for an unknown-signal name (npm dep or env stem),
295
+ * or null when the signal is unlisted or listed as a demanded (loud) gap. Exported for init,
296
+ * whose plan partitions the same signals the proof does.
297
+ *
298
+ * DEMANDED ANYWHERE WINS: the unknown map merges npm deps, env stems and registry-host ids
299
+ * under one key space, so a name listed in BOTH registry sections must never let one
300
+ * section's acknowledgment quiet the other's demanded gap (§9 round two H5, 2026-08-31: an
301
+ * acknowledged dep entry silently green-lit a repo whose only signal was the same-named
302
+ * DEMANDED env stem). Loud beats quiet; the gate also refuses conflicting dispositions. */
303
+ export function registryAcknowledgedReason(name: string): string | null {
304
+ const registry = knownExternalServices();
305
+ const entries = [registry.deps[name], registry.envStems[name]].filter(
306
+ (entry): entry is PacklessEntry => entry !== undefined,
307
+ );
308
+ if (entries.length === 0 || entries.some((entry) => entry.disposition !== 'acknowledged')) return null;
309
+ return entries[0]!.reason;
310
+ }
311
+
312
+ export type WorldTwinId = {
313
+ /** display label (e.g. 'stripe (twin service)') */
314
+ label: string;
315
+ /** whether traffic can actually REACH the twin behind this identifier: the injector/proxy
316
+ * intercepts its vendor hosts, or the service exposes app-read endpoint env. A twin that is
317
+ * merely present — reachable by nothing — must not count as coverage (the LibreChat
318
+ * AWS_TWIN_URL trap: the injectEnv looked wired but the injector reads no `aws` vendor). */
319
+ interceptable: boolean;
320
+ };
321
+
322
+ type WorldTwinInventory = {
323
+ source: 'instance' | 'config';
324
+ path: string;
325
+ /** normalized identifier → id record (e.g. 'stripe' → { label: 'stripe (service)', … }) */
326
+ ids: Map<string, WorldTwinId>;
327
+ };
328
+
329
+ function addId(ids: Map<string, WorldTwinId>, key: string, label: string, interceptable: boolean): void {
330
+ const existing = ids.get(key);
331
+ if (!existing) ids.set(key, { label, interceptable });
332
+ // first label wins (stable output), but interceptability is an OR across contributors: a
333
+ // second service that CAN be reached upgrades the id.
334
+ else if (interceptable && !existing.interceptable) existing.interceptable = true;
335
+ }
336
+
337
+ function addServiceIds(
338
+ ids: Map<string, WorldTwinId>,
339
+ service: {
340
+ id: string;
341
+ type?: string;
342
+ injectEnv?: string;
343
+ injectEnvTemplates?: Record<string, string>;
344
+ cliRedirect?: unknown;
345
+ /** instance-path services carry their injected vars here instead of the config fields */
346
+ env?: Record<string, string>;
347
+ command?: string | string[];
348
+ args?: string[];
349
+ colocate?: { module: string };
350
+ },
351
+ ): void {
352
+ const type = service.type ?? 'twin';
353
+ const commandParts = [
354
+ ...(Array.isArray(service.command) ? service.command : service.command ? [service.command] : []),
355
+ ...(service.args ?? []),
356
+ ...(service.colocate ? [service.colocate.module] : []),
357
+ ];
358
+ const packNames = commandParts.flatMap((part) => {
359
+ const fromPath = part.match(/packages\/twin\/([a-z0-9-]+)\//);
360
+ const fromBin = part.match(/^world-([a-z0-9-]+)$/);
361
+ const fromPkg = part.match(/^@volter\/twin-([a-z0-9-]+)$/);
362
+ return [fromPath?.[1], fromBin?.[1], fromPkg?.[1]].filter((name): name is string => name !== undefined);
363
+ });
364
+ // How would traffic actually reach this twin?
365
+ // • the injector/ambient proxy intercepts its vendor hosts — true when its injectEnv is a
366
+ // `*_TWIN_URL` var the injector reads, or its service id / pack name IS an injector
367
+ // vendor key (the consolidated aws twin's `s3` service id, for example);
368
+ // • OR the app/CLI reads its endpoint env directly — external services (discovered env),
369
+ // injectEnvTemplates (LIVEKIT_URL=…), cliRedirect, or a non-`*_TWIN_URL` injectEnv.
370
+ // A twin service with NEITHER is present but unreachable: interceptable=false.
371
+ const vendorKeys = new Set([...injectableVendorKeys()].map(normalizeId));
372
+ const envKeys = Object.keys(service.env ?? {}); // instance-path evidence of the same wiring
373
+ const injectorReads =
374
+ (service.injectEnv !== undefined && twinUrlVendorFor(service.injectEnv) !== null) ||
375
+ envKeys.some((key) => twinUrlVendorFor(key) !== null);
376
+ const appConfigured =
377
+ type === 'external' ||
378
+ service.cliRedirect !== undefined ||
379
+ Object.keys(service.injectEnvTemplates ?? {}).length > 0 ||
380
+ (service.injectEnv !== undefined && !/_TWIN_URL$/.test(service.injectEnv)) ||
381
+ envKeys.some((key) => !/_TWIN_URL$/.test(key));
382
+ const hostMatched =
383
+ vendorKeys.has(normalizeId(service.id)) || packNames.some((pack) => vendorKeys.has(normalizeId(pack)));
384
+ const interceptable = injectorReads || appConfigured || hostMatched;
385
+ // twin + external services cover their vendor by identity; a plain 'process'
386
+ // service only counts via an explicit twin marker (injectEnv/*_TWIN_URL, pack path).
387
+ if (type === 'twin' || type === 'external') {
388
+ const label = type === 'twin' ? `${service.id} (twin service)` : `${service.id} (external service)`;
389
+ addId(ids, normalizeId(service.id), label, interceptable);
390
+ }
391
+ if (service.injectEnv) {
392
+ const stem = service.injectEnv.match(/^(.+)_TWIN_URL$/);
393
+ if (stem) addId(ids, normalizeId(stem[1]!), `${service.id} (${service.injectEnv})`, interceptable);
394
+ }
395
+ for (const pack of packNames) {
396
+ addId(ids, normalizeId(pack), `${service.id} (pack ${pack})`, interceptable);
397
+ }
398
+ }
399
+
400
+ /** The twins actually IN the named world: instance first (the booted truth), stable
401
+ * config as the pre-boot fallback. Throws loudly when the world resolves to neither. */
402
+ export function worldTwinInventory(world: string, root: string): WorldTwinInventory {
403
+ let instanceError: string | undefined;
404
+ try {
405
+ const status = statusWorld(world, root);
406
+ const ids = new Map<string, WorldTwinId>();
407
+ for (const service of Object.values(status.services)) addServiceIds(ids, service);
408
+ for (const key of Object.keys(status.env)) {
409
+ const stem = key.match(/^(.+)_TWIN_URL$/);
410
+ // a bare env `*_TWIN_URL` var is only a REACHABLE twin when the injector reads it
411
+ if (stem) addId(ids, normalizeId(stem[1]!), `env ${key}`, twinUrlVendorFor(key) !== null);
412
+ }
413
+ return { source: 'instance', path: `${status.dirs.instance}/instance.json`, ids };
414
+ } catch (error) {
415
+ instanceError = error instanceof Error ? error.message : String(error);
416
+ }
417
+ try {
418
+ const { path, config } = loadWorldConfig(world, root);
419
+ const ids = new Map<string, WorldTwinId>();
420
+ for (const service of config.services as WorldServiceConfig[]) addServiceIds(ids, service);
421
+ return { source: 'config', path, ids };
422
+ } catch (error) {
423
+ const configError = error instanceof Error ? error.message : String(error);
424
+ throw new Error(
425
+ `volter-world covers: world "${world}" not found as an instance or a config.\n` +
426
+ ` instance: ${instanceError}\n config: ${configError}`,
427
+ );
428
+ }
429
+ }
430
+
431
+ export type CoverageOptions = {
432
+ root?: string;
433
+ allowUnknown?: boolean;
434
+ /**
435
+ * vendor → reason: vendors the operator ACKNOWLEDGES need no twin in this world — e.g. an SDK
436
+ * used verifier-only (svix's Webhook verifies incoming signatures locally and never calls out).
437
+ * An acknowledged vendor downgrades missing/unknown-sdk to status 'acknowledged' (reason shown,
438
+ * never silent); a reason is REQUIRED — an empty one throws.
439
+ *
440
+ * UNINTERCEPTABLE splits in two (the Cal.com svix finding):
441
+ * • an injector vendor key EXISTS for the vendor and the wiring is merely wrong (the LibreChat
442
+ * AWS_TWIN_URL trap) — a config bug, NOT acknowledgeable: the acknowledgment is refused
443
+ * loudly on the row and the proof stays red until the wiring is fixed;
444
+ * • NO injector key exists at all (the pack is in its descriptor's hostsNone ruling
445
+ * allowlist — ~15 packs wire by explicit endpoint config only) — acknowledgeable WITH a
446
+ * reason. Before this, the only route to green was DELETING the twin from the world and
447
+ * acknowledging it as un-twinned, which made the config LESS truthful than the red proof.
448
+ */
449
+ acknowledge?: Record<string, string>;
450
+ };
451
+
452
+ /** What a repo BETRAYS about the external services it talks to — the repo half of the coverage
453
+ * proof, split out so `init` (which must EMIT a twin per detected vendor) and `covers` (which must
454
+ * PROVE one exists) can never drift apart by re-encoding detection twice. */
455
+ export type RepoVendorSignals = {
456
+ /** vendor key → the sources that betrayed it (`npm: stripe`, `env: STRIPE_SECRET_KEY`,
457
+ * `fetch: src/billing.ts:12 -> api.stripe.com`) */
458
+ detected: Map<string, string[]>;
459
+ /** external-service-shaped signal with NO vendor mapping → its sources (dep name, or env stem) */
460
+ unknown: Map<string, string[]>;
461
+ };
462
+
463
+ /** Detect every vendor (and every unmapped external-service-shaped signal) an application repo
464
+ * betrays: mapped npm dependencies across the root + all workspace members, vendor-shaped env
465
+ * names in committed `.env*` files, the SMTP/raw-protocol signal, and literal vendor URLs passed
466
+ * directly to fetch in production source. URL attribution reads the injector's VENDOR_HOSTS table
467
+ * rather than re-encoding host rules here. Insertion order follows the sorted dependency, env-name,
468
+ * and source lists, so callers that preserve it are deterministic. */
469
+ export function detectRepoVendors(repoPath: string): RepoVendorSignals {
470
+ const repo = resolve(repoPath);
471
+ const dependencies = projectDependencies(repo);
472
+ const envNames = projectEnvNames(repo);
473
+ const npmRegistries = projectNpmRegistries(repo);
474
+
475
+ // vendor → detection sources
476
+ const detected = new Map<string, string[]>();
477
+ const mappedDeps = new Set<string>();
478
+ for (const dependency of dependencies) {
479
+ // `pypi:<name>` is the Python half (project-inspect's PYPI_TWINS, descriptors' adoption.pypi).
480
+ const py = dependency.startsWith('pypi:') ? dependency.slice(5) : undefined;
481
+ const vendor = py !== undefined ? PYPI_TWINS[py]?.vendor : (SDK_TWINS[dependency]?.vendor ?? scopeVendorFor(dependency));
482
+ if (vendor === undefined) continue;
483
+ mappedDeps.add(dependency);
484
+ detected.set(vendor, [...(detected.get(vendor) ?? []), py !== undefined ? `pypi: ${py}` : `npm: ${dependency}`]);
485
+ }
486
+ for (const name of envNames) {
487
+ if (/_TWIN_URL$/.test(name) || /^VOLTER_/.test(name)) continue;
488
+ // The raw-protocol mail path. This used to fall through to `unknown` because no SMTP twin
489
+ // existed, which was the honest answer THEN; the `smtp` pack now twins it, so the same signal
490
+ // is a DETECTED vendor and a world carrying an smtp service covers it. (The env NAME is the
491
+ // whole interception story here — there is no host for the injector to rewrite, so
492
+ // SMTP_HOST/EMAIL_SERVER_HOST pointed at the twin's listener is what redirects the app.)
493
+ if (isSmtpEnvSignal(name)) {
494
+ // NB this sits BEFORE the stem lookup, so a vendor-NAMED mail host (`POSTMARK_SMTP_HOST`,
495
+ // `MAILGUN_SMTP_HOST`) attributes to the `smtp` twin rather than to that vendor's HTTP pack.
496
+ // Deliberate: the var names an SMTP endpoint, and pointing it at the twin's listener is what
497
+ // actually redirects the mail — postmark's REST twin would not receive it.
498
+ detected.set('smtp', [...(detected.get('smtp') ?? []), `env: ${name}`]);
499
+ continue;
500
+ }
501
+ const stem = envVendorStem(name, ENV_SUFFIX_BROAD);
502
+ const vendor = stem === null ? undefined : ENV_STEM_VENDORS[stem];
503
+ if (vendor) detected.set(vendor, [...(detected.get(vendor) ?? []), `env: ${name}`]);
504
+ }
505
+
506
+ // The npm registry injector deliberately owns only npmjs.org and GitHub Packages. A custom
507
+ // configured registry is a distinct uncovered destination even when NPM_TOKEN also detects the
508
+ // official npm twin; treating the credential as coverage would silently send private-registry
509
+ // traffic to the real network.
510
+ const officialNpmHosts = new Set(['registry.npmjs.org', 'npm.pkg.github.com']);
511
+ for (const registry of npmRegistries) {
512
+ const hostname = new URL(registry.url).hostname.toLowerCase();
513
+ if (officialNpmHosts.has(hostname)) {
514
+ detected.set('npm-registry', [...(detected.get('npm-registry') ?? []), `registry: ${registry.source} -> ${hostname}`]);
515
+ }
516
+ }
517
+
518
+ // Raw-fetch vendor discovery. A hand-written client has no SDK dependency, and its credential
519
+ // may use a project-specific name; the literal destination is the one unambiguous signal left.
520
+ // Match it through the injector's OWN predicates, including pathname-aware shared hosts.
521
+ const knownVendorById = new Map<string, string>();
522
+ for (const vendor of [
523
+ ...Object.values(SDK_TWINS).map((entry) => entry.vendor),
524
+ ...Object.values(ENV_STEM_VENDORS),
525
+ ...Object.keys(VENDOR_WORLD_IDS),
526
+ ]) knownVendorById.set(normalizeId(vendor), vendor);
527
+ const canonicalVendor = (injectorKey: string): string | null => {
528
+ const key = normalizeId(injectorKey);
529
+ for (const [vendor, ids] of Object.entries(VENDOR_WORLD_IDS)) {
530
+ if (ids.includes(key)) return vendor;
531
+ }
532
+ return knownVendorById.get(key) ?? null;
533
+ };
534
+ const vendorHosts = loadInject().VENDOR_HOSTS;
535
+ for (const signal of projectFetchUrls(repo)) {
536
+ const url = new URL(signal.url);
537
+ const vendors = new Set<string>();
538
+ for (const [injectorKey, matches] of Object.entries(vendorHosts)) {
539
+ if (!matches(url.hostname, url.pathname)) continue;
540
+ const vendor = canonicalVendor(injectorKey);
541
+ if (vendor !== null) vendors.add(vendor);
542
+ }
543
+ for (const vendor of [...vendors].sort()) {
544
+ const source = `fetch: ${signal.source} -> ${url.hostname}`;
545
+ detected.set(vendor, [...(detected.get(vendor) ?? []), source]);
546
+ }
547
+ }
548
+
549
+ // unknown external-service-shaped signals (no vendor mapping). A dep from a scope with a
550
+ // twin-mapped sibling counts even when its own name is not service-shaped — the Dub run's
551
+ // @upstash/redis + @upstash/ratelimit disappeared exactly here while @upstash/qstash mapped.
552
+ const unknown = new Map<string, string[]>();
553
+ for (const registry of npmRegistries) {
554
+ const hostname = new URL(registry.url).hostname.toLowerCase();
555
+ if (officialNpmHosts.has(hostname)) continue;
556
+ const id = `npm-registry@${hostname}`;
557
+ unknown.set(id, [...(unknown.get(id) ?? []), `registry: ${registry.source} -> ${hostname}`]);
558
+ }
559
+ for (const dependency of dependencies) {
560
+ if (mappedDeps.has(dependency)) continue;
561
+ if (isExternalServiceShapedDep(dependency) || isMappedScopeSibling(dependency)) {
562
+ unknown.set(dependency, [...(unknown.get(dependency) ?? []), `npm: ${dependency}`]);
563
+ }
564
+ }
565
+ for (const name of envNames) {
566
+ if (/_TWIN_URL$/.test(name) || /^VOLTER_/.test(name)) continue;
567
+ if (isSmtpEnvSignal(name)) continue; // now a DETECTED vendor (above), no longer an unknown
568
+ const stem = envVendorStem(name, ENV_SUFFIX_STRICT);
569
+ if (stem === null || ENV_STEM_VENDORS[stem] || ENV_STEM_IGNORE.has(stem)) continue;
570
+ // The registry's notExternal suppressions apply to ENV STEMS too — the census adjudicated
571
+ // 40 app-internal stems ("names no vendor") that this loop kept flagging because only the
572
+ // dep-side checks consulted the registry (§9 round two H4, 2026-08-31: 17 of 18 formally
573
+ // dead stems still failed the proof).
574
+ if (knownExternalServices().notExternal[stem] !== undefined) continue;
575
+ unknown.set(stem, [...(unknown.get(stem) ?? []), `env: ${name}`]);
576
+ }
577
+ return { detected, unknown };
578
+ }
579
+
580
+ export function coverWorld(world: string, repoPath: string, options: CoverageOptions = {}): CoverageReport {
581
+ const root = resolve(options.root ?? process.cwd());
582
+ const allowUnknown = options.allowUnknown ?? false;
583
+ const acknowledge = options.acknowledge ?? {};
584
+ for (const [vendor, reason] of Object.entries(acknowledge)) {
585
+ if (!reason.trim()) throw new Error(`covers: --acknowledge ${vendor} requires a non-empty reason (vendor=reason)`);
586
+ }
587
+ const repo = resolve(repoPath);
588
+ const inventory = worldTwinInventory(world, root);
589
+
590
+ const { detected, unknown: unknownSources } = detectRepoVendors(repo);
591
+
592
+ // Does ANY injector vendor key exist for this vendor? Decides whether an UNINTERCEPTABLE
593
+ // finding is acknowledgeable: a key that exists means the twin COULD be intercepted and the
594
+ // wiring is merely wrong (fix it, don't acknowledge it); no key at all means the pack is a
595
+ // stated vendor-hosts allowlist gap (explicit-endpoint wiring only) and a world that still
596
+ // declares the twin may honestly acknowledge the finding rather than delete the twin.
597
+ const injectorKeysFor = injectorVendorKeysFor;
598
+
599
+ const rows: CoverageRow[] = [];
600
+ const covered: string[] = [];
601
+ const acknowledged: { vendor: string; reason: string }[] = [];
602
+ const missing: string[] = [];
603
+ const uninterceptable: string[] = [];
604
+ for (const [vendor, sources] of [...detected.entries()].sort(([a], [b]) => a.localeCompare(b))) {
605
+ // a vendor is only COVERED by a twin traffic can actually reach; a present-but-unreachable
606
+ // twin (no injector vendor, no app-read endpoint env) is a distinct, failing status.
607
+ const candidates = worldIdsFor(vendor).filter((id) => inventory.ids.has(id));
608
+ const matchId = candidates.find((id) => inventory.ids.get(id)!.interceptable) ?? candidates[0];
609
+ const match = matchId === undefined ? null : inventory.ids.get(matchId)!;
610
+ let status: CoverageStatus = match === null ? 'missing' : match.interceptable ? 'covered' : 'uninterceptable';
611
+ let ackRefused: string | undefined;
612
+ if (acknowledge[vendor] !== undefined) {
613
+ if (status === 'missing') status = 'acknowledged';
614
+ else if (status === 'uninterceptable') {
615
+ const keys = injectorKeysFor(vendor);
616
+ if (keys.length === 0) status = 'acknowledged';
617
+ else {
618
+ ackRefused =
619
+ `acknowledge REFUSED: injector key(s) ${keys.join('/')} exist for this vendor — the twin CAN be intercepted, ` +
620
+ `the wiring is merely wrong. Fix it (${keys.map(injectorEnvNameForKey).join(' / ')}) instead of acknowledging`;
621
+ }
622
+ }
623
+ }
624
+ if (status === 'covered') covered.push(vendor);
625
+ else if (status === 'missing') missing.push(vendor);
626
+ else if (status === 'acknowledged') acknowledged.push({ vendor, reason: acknowledge[vendor]! });
627
+ else uninterceptable.push(vendor);
628
+ rows.push({
629
+ vendor,
630
+ detectedVia:
631
+ status === 'acknowledged'
632
+ ? [...sources, `acknowledged: ${acknowledge[vendor]}`]
633
+ : ackRefused !== undefined
634
+ ? [...sources, ackRefused]
635
+ : sources,
636
+ twinInWorld: match === null ? null : match.label,
637
+ status,
638
+ });
639
+ }
640
+ const unknown: string[] = [];
641
+ for (const [name, sources] of [...unknownSources.entries()].sort(([a], [b]) => a.localeCompare(b))) {
642
+ if (acknowledge[name] !== undefined) {
643
+ acknowledged.push({ vendor: name, reason: acknowledge[name]! });
644
+ rows.push({ vendor: name, detectedVia: [...sources, `acknowledged: ${acknowledge[name]}`], twinInWorld: null, status: 'acknowledged' });
645
+ continue;
646
+ }
647
+ // STANDING acknowledgments from the packless-vendor registry: a signal the census rulings
648
+ // adjudicated acceptable (config-time adapters, per-repo-judged surfaces) acknowledges
649
+ // itself with the RECORDED reason — the same status a per-run `--acknowledge` grants, but
650
+ // sourced from committed adjudication instead of a flag. Demanded registry entries fall
651
+ // through to unknown-sdk on purpose: known-but-packless is still an uncovered vendor.
652
+ const standing = registryAcknowledgedReason(name);
653
+ if (standing !== null) {
654
+ acknowledged.push({ vendor: name, reason: standing });
655
+ rows.push({ vendor: name, detectedVia: [...sources, `acknowledged (registry): ${standing}`], twinInWorld: null, status: 'acknowledged' });
656
+ continue;
657
+ }
658
+ unknown.push(name);
659
+ rows.push({ vendor: name, detectedVia: sources, twinInWorld: null, status: 'unknown-sdk' });
660
+ }
661
+
662
+ return {
663
+ world,
664
+ worldSource: inventory.source,
665
+ worldPath: inventory.path,
666
+ repo,
667
+ twinsInWorld: [...inventory.ids.values()].map((id) => id.label).sort(),
668
+ rows,
669
+ covered,
670
+ missing,
671
+ uninterceptable,
672
+ unknown,
673
+ acknowledged,
674
+ allowUnknown,
675
+ ok: missing.length === 0 && uninterceptable.length === 0 && (allowUnknown || unknown.length === 0),
676
+ };
677
+ }
678
+
679
+ export function formatCoverageReport(report: CoverageReport): string {
680
+ const lines: string[] = [];
681
+ lines.push(`World ${report.world} (${report.worldSource}: ${report.worldPath})`);
682
+ lines.push(`Repo ${report.repo}`);
683
+ lines.push('');
684
+ const header = ['vendor', 'detected-via', 'twin-in-world', 'status'];
685
+ const cells = report.rows.map((row) => [
686
+ row.vendor,
687
+ row.detectedVia.join('; '),
688
+ row.twinInWorld ?? '-',
689
+ row.status === 'missing' ? 'MISSING' : row.status === 'uninterceptable' ? 'UNINTERCEPTABLE' : row.status,
690
+ ]);
691
+ const widths = header.map((title, column) => Math.max(title.length, ...cells.map((row) => row[column]!.length)));
692
+ const renderRow = (row: string[]): string => row.map((cell, column) => cell.padEnd(widths[column]!)).join(' | ').trimEnd();
693
+ lines.push(renderRow(header));
694
+ lines.push(widths.map((width) => '-'.repeat(width)).join('-|-'));
695
+ for (const row of cells) lines.push(renderRow(row));
696
+ if (report.rows.length === 0) lines.push('(no external vendor dependencies detected in the repo)');
697
+ lines.push('');
698
+ if (report.missing.length > 0) {
699
+ lines.push(`NOT COVERED: ${report.missing.length} vendor(s) with no twin in world ${report.world}: ${report.missing.join(', ')}`);
700
+ lines.push(` add the missing twin service(s) to the world config, then re-run the proof.`);
701
+ }
702
+ if (report.uninterceptable.length > 0) {
703
+ lines.push(`UNINTERCEPTABLE: ${report.uninterceptable.length} vendor(s) have a twin in world ${report.world} that no traffic can reach: ${report.uninterceptable.join(', ')}`);
704
+ lines.push(` the twin is present, but its service resolves to no injector vendor (VENDOR_HOSTS in @volter/twin/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.`);
705
+ }
706
+ if (report.unknown.length > 0) {
707
+ const verdict = report.allowUnknown ? 'WARNING (allowed by --allow-unknown)' : 'UNKNOWN-SDK: fails the proof';
708
+ lines.push(`${verdict}: ${report.unknown.length} external-service-shaped signal(s) with no twin mapping: ${report.unknown.join(', ')}`);
709
+ if (!report.allowUnknown) lines.push(' map them in SDK_TWINS (packages/twin/world-runtime/src/project-inspect.ts) or rerun with --allow-unknown.');
710
+ }
711
+ // Acknowledgments are part of the verdict, not fine print: a proof that passed WITH
712
+ // acknowledged rows must say so (and how many were standing/registry vs per-run flags) —
713
+ // "COVERED" alone would overstate a world whose acknowledged vendors have no twin at all
714
+ // (§9 round two M1, 2026-08-31: CoverageReport.acknowledged had no production consumer).
715
+ if (report.acknowledged.length > 0) {
716
+ lines.push(`ACKNOWLEDGED: ${report.acknowledged.length} signal(s) accepted with recorded reasons (no twin): ${report.acknowledged.map((a) => a.vendor).join(', ')}`);
717
+ }
718
+ lines.push(report.ok
719
+ ? report.acknowledged.length > 0
720
+ ? `COVERED (with ${report.acknowledged.length} acknowledgment(s)): every other detected vendor has a twin in world ${report.world}.`
721
+ : `COVERED: every detected vendor has a twin in world ${report.world}.`
722
+ : `PROOF FAILED for world ${report.world}.`);
723
+ return `${lines.join('\n')}\n`;
724
+ }