@vibes.diy/api-svc 12.2.12 → 12.3.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibes.diy/api-svc",
3
- "version": "12.2.12",
3
+ "version": "12.3.0",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "main": "./index.js",
@@ -22,18 +22,18 @@
22
22
  "@libsql/client": "~0.17.4",
23
23
  "@neondatabase/serverless": "~1.1.0",
24
24
  "@noble/hashes": "~2.2.0",
25
- "@vibes.diy/api-pkg": "12.2.12",
26
- "@vibes.diy/api-sql": "12.2.12",
27
- "@vibes.diy/api-types": "12.2.12",
28
- "@vibes.diy/call-ai-v2": "12.2.12",
29
- "@vibes.diy/identity": "12.2.12",
30
- "@vibes.diy/prompts": "12.2.12",
31
- "@vibes.diy/vibe-db-explorer": "12.2.12",
32
- "@vibes.diy/vibe-runtime": "12.2.12",
33
- "@vibes.diy/vibe-types": "12.2.12",
25
+ "@vibes.diy/api-pkg": "12.3.0",
26
+ "@vibes.diy/api-sql": "12.3.0",
27
+ "@vibes.diy/api-types": "12.3.0",
28
+ "@vibes.diy/call-ai-v2": "12.3.0",
29
+ "@vibes.diy/identity": "12.3.0",
30
+ "@vibes.diy/prompts": "12.3.0",
31
+ "@vibes.diy/vibe-db-explorer": "12.3.0",
32
+ "@vibes.diy/vibe-runtime": "12.3.0",
33
+ "@vibes.diy/vibe-types": "12.3.0",
34
34
  "acorn": "~8.17.0",
35
35
  "arktype": "~2.2.3",
36
- "call-ai": "12.2.12",
36
+ "call-ai": "12.3.0",
37
37
  "charwise": "~3.0.1",
38
38
  "cookie": "~2.0.1",
39
39
  "csv-parse": "~7.0.1",
@@ -0,0 +1,188 @@
1
+ #!/usr/bin/env bash
2
+ # check-env.sh — validate the environment the usage-report tools need.
3
+ #
4
+ # Why this exists: most of these tools DEGRADE SILENTLY. A missing
5
+ # AUTUMN_SECRET_KEY does not error — `journey` prints "NOT in Autumn" and
6
+ # "converted: none" for every user, which reads as a real finding and is not.
7
+ # A missing CLERK_SECRET_KEY prints "(no name) (none) signup=?" and the report
8
+ # still looks complete. So "the script ran and printed a report" is NOT
9
+ # evidence the environment is right. Run this first.
10
+ #
11
+ # Usage:
12
+ # ./check-env.sh # check the current shell env (+ .dev.vars)
13
+ # ./check-env.sh --tool journey # only what `journey` needs
14
+ # pbpaste | ./check-env.sh --diff # compare a known-good env's NAMES to yours
15
+ #
16
+ # This script never prints, logs, or transmits a variable's VALUE — only
17
+ # whether a name is set. --diff reads only the text before each `=`.
18
+
19
+ set -uo pipefail
20
+
21
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
22
+ DEV_VARS="$SCRIPT_DIR/../.dev.vars"
23
+
24
+ RED=$'\033[31m'; YEL=$'\033[33m'; GRN=$'\033[32m'; DIM=$'\033[2m'; BLD=$'\033[1m'; RST=$'\033[0m'
25
+ if [ ! -t 1 ]; then RED=""; YEL=""; GRN=""; DIM=""; BLD=""; RST=""; fi
26
+
27
+ TOOL="all"
28
+ MODE="check"
29
+ while [ $# -gt 0 ]; do
30
+ case "$1" in
31
+ --tool) TOOL="${2:-all}"; shift 2 ;;
32
+ --diff) MODE="diff"; shift ;;
33
+ -h|--help) sed -n '2,20p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
34
+ *) echo "unknown arg: $1" >&2; exit 2 ;;
35
+ esac
36
+ done
37
+
38
+ # ---------------------------------------------------------------------------
39
+ # The reference set. Each entry: NAME|TOOLS|SEVERITY|what breaks without it
40
+ # SEVERITY: required = tool refuses to run · silent = tool runs and LIES · optional
41
+ # ---------------------------------------------------------------------------
42
+ SPEC=$(cat <<'SPEC_END'
43
+ NEON_DATABASE_URL|journey,db-inspect|required|Prod Neon connection. Without it `journey` exits with "NEON_DATABASE_URL is required" and `db:inspect` cannot run at all. DATABASE_URL is accepted as a fallback. This is the one failure that is loud.
44
+ AUTUMN_SECRET_KEY|journey|silent|THE BIG ONE. Billing plane (plan, credit balance, wall crossing, conversion). Missing key is INDISTINGUISHABLE in the output from a user Autumn never saw: the report prints "NOT in Autumn (customer_not_found) — no billing signal" and ">> VERDICT: no Autumn record | converted: none" for EVERY user. Every paywall casualty reads as never-walled and every subscriber reads as never-converted. If Meghan's reports say nobody converted, suspect this before believing it.
45
+ CLERK_SECRET_KEY|journey,vibe-usage|silent|Identity plane (name, email, signup date). Missing key silently yields "identity: (no name) (none) signup=?" — the rest of the report renders normally, so it looks like a user with no profile rather than a broken env. Also required by vibe-usage.py for the sign-up funnel leg.
46
+ POSTHOG_API_KEY|posthog|optional|Private HogQL query key (project 157245) for the behaviour plane — click streams, boot timing, funnel events. Only needed for PostHog work; see agents/posthog-queries.md.
47
+ CLOUDFLARE_API_TOKEN|vibe-usage|silent|Cloudflare GraphQL analytics (visitors, RefererEvents) for vibe-usage.py. There is no guard: the script sends "Bearer None", the HTTPError is caught and swallowed, the counters stay at their zero initialisers, and the last line prints "FUNNEL: ~0 visits -> N sign-ups". A zero visitor count is a plausible-looking number, not an error, so the funnel reads as a real finding about a dead app.
48
+ DISCORD_WEBHOOK|report|optional|Team Discord posting for the final "so-what" summary step of the journey runbook. Without it the analysis still runs; you just post by hand.
49
+ HUBSPOT_PRIVATE_APP_TOKEN|hubspot|silent|CRM writes/reads from the traction repo — hubspot/sync-radar.mjs (pushes radar rollups onto contacts), link-accounts.mjs (the multi-account roster on clerk_user_ids_all), event-attribution.mjs, apply-schema.mjs. Missing token means the sync half of a maker-radar pass silently does nothing, so prod and HubSpot drift apart while both look fine.
50
+ CLOUDFLARE_ACCOUNT_ID|vibe-usage|optional|Paired with CLOUDFLARE_API_TOKEN for Cloudflare GraphQL analytics and `wrangler tail`. The token alone is not enough for account-scoped queries.
51
+ NEON_DATABASE_ADMIN_URL|admin|optional|Elevated Neon role for schema/grant work (agents/neon-new-table-grants.md). Not needed for read-only journey/db:inspect work — if you only investigate users, you should NOT have this set.
52
+ CLERK_SECRET_KEY_PREVIEW|preview|optional|Clerk key for the dev+preview data plane, which is a SEPARATE Clerk instance from prod. Only for preview-env validation work; a prod user investigation must use CLERK_SECRET_KEY or it will find nothing.
53
+ VIBES_DEVICE_ID|preview|optional|Device identity for CLI/headless flows against prod (agents/identity-ship-verify.md).
54
+ VIBES_DEVICE_ID_PREVIEW|preview|optional|Same, for PR-preview validation (agents/pr-lifecycle.md). Preview and prod are different data planes — the prod device id will not authenticate against a preview.
55
+ LLM_BACKEND_URL|eval|optional|Codegen eval harnesses (eval/skill-lanes, codegen matrix). Nothing in the usage-report lane needs it.
56
+ LLM_BACKEND_API_KEY|eval|optional|Companion to LLM_BACKEND_URL. Eval lanes only.
57
+ DISCORD_PUBLIC_WEBHOOK|report|optional|The PUBLIC Discord channel — distinct from DISCORD_WEBHOOK (team). Never post a user investigation here; radar output names handles and links apps, and the public channel is the wrong audience for it.
58
+ MAILCHIMP_API_KEY|legacy|optional|No script in either repo reads this. The newsletter sender question (Mailchimp vs HubSpot) is still undecided — traction issue #13 — so this is a credential held in advance of a decision, not a dependency. Nothing breaks without it.
59
+ GA4_PROPERTY_ID|legacy|optional|STALE. Google Analytics was retired in favour of PostHog as the single analytics sink (#4257) and nothing in either repo reads this. Safe to delete from your env; if you are reaching for it, you want POSTHOG_API_KEY.
60
+ GA4_SA_KEY|legacy|optional|STALE — same as GA4_PROPERTY_ID. A Google service-account key with no remaining consumer; worth deleting rather than carrying a live credential nothing uses.
61
+ SPEC_END
62
+ )
63
+
64
+ # A var counts as present only if its EFFECTIVE value is non-empty. .dev.vars is
65
+ # parsed exactly the way loadDevVars() does — first occurrence wins, surrounding
66
+ # quotes stripped — because AUTUMN_SECRET_KEY="" loads as an empty string, and
67
+ # user-journey.ts then skips the Autumn calls just as if the key were absent.
68
+ # Reporting that as OK would greenlight the precise failure this script exists
69
+ # to catch. The value is tested inside awk and never enters a shell variable.
70
+ devvar_has() {
71
+ [ -f "$DEV_VARS" ] || return 1
72
+ awk -v key="$1" '
73
+ !seen {
74
+ line = $0
75
+ sub(/^[[:space:]]+/, "", line); sub(/[[:space:]]+$/, "", line)
76
+ if (line == "" || substr(line, 1, 1) == "#") next
77
+ p = index(line, "="); if (p <= 1) next
78
+ k = substr(line, 1, p - 1)
79
+ sub(/^[[:space:]]+/, "", k); sub(/[[:space:]]+$/, "", k)
80
+ if (k != key) next
81
+ seen = 1
82
+ v = substr(line, p + 1)
83
+ sub(/^[[:space:]]+/, "", v); sub(/[[:space:]]+$/, "", v)
84
+ if (length(v) >= 2) {
85
+ f = substr(v, 1, 1); l = substr(v, length(v), 1)
86
+ if ((f == "\"" && l == "\"") || (f == "'"'"'" && l == "'"'"'")) v = substr(v, 2, length(v) - 2)
87
+ }
88
+ if (v != "") found = 1
89
+ }
90
+ END { exit(found ? 0 : 1) }
91
+ ' "$DEV_VARS"
92
+ }
93
+
94
+ # Reject an unknown --tool rather than filtering every row away and calling the
95
+ # empty result a pass.
96
+ if [ "$TOOL" != "all" ]; then
97
+ KNOWN=$(printf '%s\n' "$SPEC" | cut -d'|' -f2 | tr ',' '\n' | sort -u)
98
+ if ! printf '%s\n' "$KNOWN" | grep -qx "$TOOL"; then
99
+ echo "${RED}unknown --tool '$TOOL'${RST}" >&2
100
+ echo "supported: all $(printf '%s ' $KNOWN)" >&2
101
+ exit 2
102
+ fi
103
+ fi
104
+
105
+ # ---------------------------------------------------------------------------
106
+ # --diff : read a known-good env on stdin, compare NAMES only.
107
+ # ---------------------------------------------------------------------------
108
+ if [ "$MODE" = "diff" ]; then
109
+ REF_NAMES=$(grep -oE '^[[:space:]]*(export[[:space:]]+)?[A-Za-z_][A-Za-z0-9_]*=' \
110
+ | sed -E 's/^[[:space:]]*(export[[:space:]]+)?//; s/=$//' | sort -u)
111
+ if [ -z "$REF_NAMES" ]; then
112
+ echo "${RED}No VAR= lines found on stdin.${RST} Expected `env`-style output, e.g. pbpaste | $0 --diff" >&2
113
+ exit 2
114
+ fi
115
+ echo "${BLD}Names present in the reference env but not in yours${RST} ${DIM}(values never read)${RST}"
116
+ echo
117
+ missing=0
118
+ while IFS= read -r name; do
119
+ [ -z "$name" ] && continue
120
+ if [ -z "${!name:-}" ]; then
121
+ # Note text itself contains "|", so take everything after the 3rd field.
122
+ note=$(printf '%s\n' "$SPEC" | grep "^${name}|" | cut -d'|' -f4-)
123
+ printf ' %sMISSING%s %s\n' "$RED" "$RST" "$name"
124
+ [ -n "$note" ] && printf ' %s%s%s\n' "$DIM" "$note" "$RST"
125
+ missing=$((missing+1))
126
+ fi
127
+ done <<< "$REF_NAMES"
128
+ [ "$missing" -eq 0 ] && echo " ${GRN}Nothing missing.${RST} Your env has every name the reference env has."
129
+ echo
130
+ echo "${DIM}Reference env had $(printf '%s\n' "$REF_NAMES" | wc -l | tr -d ' ') names; $missing not set here.${RST}"
131
+ exit 0
132
+ fi
133
+
134
+ # ---------------------------------------------------------------------------
135
+ # Default mode: check against the reference spec.
136
+ # ---------------------------------------------------------------------------
137
+ echo "${BLD}usage-report environment check${RST}"
138
+ if [ -f "$DEV_VARS" ]; then
139
+ echo "${DIM}.dev.vars found at api/svc/.dev.vars — the TS tools load it as a fallback, so vars set there count as present.${RST}"
140
+ else
141
+ echo "${DIM}No api/svc/.dev.vars — every var must come from the shell env.${RST}"
142
+ fi
143
+ echo
144
+
145
+ fail=0; silent=0; warn=0
146
+ while IFS='|' read -r name tools sev note; do
147
+ [ -z "$name" ] && continue
148
+ case "$TOOL" in
149
+ all) ;;
150
+ *) printf '%s' ",$tools," | grep -q ",$TOOL," || continue ;;
151
+ esac
152
+
153
+ src=""
154
+ if [ -n "${!name:-}" ]; then
155
+ src="shell env"
156
+ elif devvar_has "$name"; then
157
+ src=".dev.vars"
158
+ fi
159
+
160
+ if [ -n "$src" ]; then
161
+ printf ' %sOK%s %-24s %s(%s)%s\n' "$GRN" "$RST" "$name" "$DIM" "$src" "$RST"
162
+ continue
163
+ fi
164
+
165
+ # NEON_DATABASE_URL has an accepted fallback.
166
+ if [ "$name" = "NEON_DATABASE_URL" ] && { [ -n "${DATABASE_URL:-}" ] || devvar_has DATABASE_URL; }; then
167
+ printf ' %sOK%s %-24s %s(via DATABASE_URL fallback)%s\n' "$GRN" "$RST" "$name" "$DIM" "$RST"
168
+ continue
169
+ fi
170
+
171
+ case "$sev" in
172
+ required) printf ' %sMISSING%s %-24s %sthe tool will refuse to run%s\n' "$RED" "$RST" "$name" "$RED" "$RST"; fail=$((fail+1)) ;;
173
+ silent) printf ' %sMISSING%s %-24s %sSILENT — the tool still prints a report, and it is wrong%s\n' "$RED" "$RST" "$name" "$YEL" "$RST"; silent=$((silent+1)) ;;
174
+ *) printf ' %s--%s %-24s %soptional%s\n' "$YEL" "$RST" "$name" "$DIM" "$RST"; warn=$((warn+1)) ;;
175
+ esac
176
+ printf ' %s%s%s\n' "$DIM" "$note" "$RST"
177
+ done <<< "$SPEC"
178
+
179
+ echo
180
+ if [ "$fail" -gt 0 ] || [ "$silent" -gt 0 ]; then
181
+ echo "${RED}${BLD}NOT SAFE TO TRUST REPORTS${RST}: $fail hard-missing, $silent silently-degrading."
182
+ [ "$silent" -gt 0 ] && echo "${YEL}The silent ones are why a report can look complete and still be wrong.${RST}"
183
+ echo "Ask jchris for the missing values — they are secrets, so they arrive out-of-band, never in a repo file or a chat log."
184
+ exit 1
185
+ fi
186
+ msg="${GRN}Environment is complete for: $TOOL${RST}"
187
+ [ "$warn" -gt 0 ] && msg="$msg ${DIM}($warn optional not set)${RST}"
188
+ echo "$msg"
@@ -95,8 +95,26 @@ async function run() {
95
95
  const connectionString = process.env["NEON_DATABASE_URL"] ?? process.env["DATABASE_URL"];
96
96
  if (connectionString === undefined)
97
97
  return Result.Err("NEON_DATABASE_URL is required (prod Neon)");
98
+ const skipBilling = process.argv.includes("--skip-billing");
99
+ const skipIdentity = process.argv.includes("--skip-identity");
100
+ const present = (v) => v !== undefined && v !== "";
98
101
  const autumnKey = process.env["AUTUMN_SECRET_KEY"];
99
102
  const clerkKey = process.env["CLERK_SECRET_KEY"];
103
+ if (!present(autumnKey) && !skipBilling) {
104
+ return Result.Err("AUTUMN_SECRET_KEY is missing — refusing to run.\n" +
105
+ " Without it the billing plane is skipped and the report would claim\n" +
106
+ " 'no Autumn record / converted: none' for EVERY user, which is\n" +
107
+ " indistinguishable from a real finding.\n" +
108
+ " Fix your env (usage-report/check-env.sh --tool journey), or pass\n" +
109
+ " --skip-billing to accept a DB-only report.");
110
+ }
111
+ if (!present(clerkKey) && !skipIdentity) {
112
+ return Result.Err("CLERK_SECRET_KEY is missing — refusing to run.\n" +
113
+ " Without it every user reports as '(no name) (none) signup=?', which\n" +
114
+ " looks like a sparse profile rather than a broken environment.\n" +
115
+ " Fix your env (usage-report/check-env.sh --tool journey), or pass\n" +
116
+ " --skip-identity to accept a report with no identity line.");
117
+ }
100
118
  const pool = new Pool({ connectionString });
101
119
  const result = await exception2Result(async () => {
102
120
  let userId = who;
@@ -190,7 +208,9 @@ async function run() {
190
208
  L.push(`\n=== USER JOURNEY: ${who} ===`);
191
209
  L.push(`userId: ${userId}`);
192
210
  L.push(`handles: ${handles.join(", ") || "(none)"}`);
193
- L.push(`identity: ${name ?? "(no name)"} ${redactEmail(email)} signup=${signup ?? "?"}`);
211
+ L.push(skipIdentity
212
+ ? `identity: SKIPPED (--skip-identity) — no Clerk lookup ran; this is not "user has no profile"`
213
+ : `identity: ${name ?? "(no name)"} ${redactEmail(email)} signup=${signup ?? "?"}`);
194
214
  L.push(`\n-- spend timeline (PromptContexts, truth) --`);
195
215
  L.push(`lifetime: ${asNumber(Number(summary.lifetime_credits)) ?? 0} credits over ${summary.turns} turns / ${summary.chats} chats / ${summary.active_days} active days`);
196
216
  L.push(`window: first=${ms(asString(summary.first_turn))} last=${ms(asString(summary.last_turn))}`);
@@ -200,7 +220,11 @@ async function run() {
200
220
  for (const r of appsRes.rows)
201
221
  L.push(` ${r.appSlug} (@${r.created.slice(0, 10)})`);
202
222
  L.push(`\n-- billing / wall / conversion (Autumn, read-only) --`);
203
- if (!autumnKnown) {
223
+ if (skipBilling) {
224
+ L.push(` SKIPPED (--skip-billing) — Autumn was never queried. Nothing below says anything`);
225
+ L.push(` about whether this user was walled or converted; do not read it as "none".`);
226
+ }
227
+ else if (!autumnKnown) {
204
228
  L.push(` NOT in Autumn (customer_not_found) — no billing signal. Prod tracking began ~2026-07-11;`);
205
229
  L.push(` pre-tracking users have no confirmable wall or conversion. Wall below is DB-inferred only.`);
206
230
  }
@@ -212,7 +236,9 @@ async function run() {
212
236
  L.push(` FREE ${FREE_GRANT}-wall crossed at: ${free.crossedAt !== undefined ? ms(free.crossedAt) : "NOT reached"} (period spend ${free.total} cr, app=${wallApp ?? "?"})`);
213
237
  if (plus !== undefined)
214
238
  L.push(` PLUS ${PLUS_GRANT}-wall crossed at: ${plus.crossedAt !== undefined ? ms(plus.crossedAt) : "NOT reached"} (period spend ${plus.total} cr)`);
215
- L.push(`\n>> VERDICT: ${walledNow ? "currently WALLED" : autumnKnown ? "not currently walled" : "no Autumn record"} | converted: ${converted}`);
239
+ L.push(skipBilling
240
+ ? `\n>> VERDICT: billing UNKNOWN (--skip-billing) | converted: UNKNOWN`
241
+ : `\n>> VERDICT: ${walledNow ? "currently WALLED" : autumnKnown ? "not currently walled" : "no Autumn record"} | converted: ${converted}`);
216
242
  if (free.crossedAt !== undefined && plusStarted !== undefined && plusStarted > new Date(free.crossedAt).getTime()) {
217
243
  const hrs = (plusStarted - new Date(free.crossedAt).getTime()) / 3.6e6;
218
244
  L.push(`>> free-wall -> Plus in ${hrs.toFixed(1)}h (${(hrs / 24).toFixed(2)}d)`);
@@ -1 +1 @@
1
- {"version":3,"file":"user-journey.js","sourceRoot":"","sources":["../../jsr/usage-report/user-journey.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"user-journey.js","sourceRoot":"","sources":["../../jsr/usage-report/user-journey.ts"],"names":[],"mappings":"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"}
@@ -15,12 +15,19 @@ Usage:
15
15
  OWNER=owner APP_SLUG=my-app CF_PATH='/vibe/owner/my-app%' python3 vibe-usage.py 168
16
16
 
17
17
  Requires env (present in cloud sessions): CLOUDFLARE_API_TOKEN, CLERK_SECRET_KEY.
18
+ Both are ENFORCED — a missing key exits 2 rather than zeroing a leg of the
19
+ funnel. Check with usage-report/check-env.sh --tool vibe-usage; opt out of a
20
+ leg deliberately with --skip-visitors / --skip-signups.
18
21
  Postgres goes through the repo's db:inspect (prod, read-only).
19
22
  """
20
23
  import json, os, subprocess, sys, urllib.request, urllib.error
21
24
  from datetime import datetime, timedelta, timezone
22
25
 
23
- HOURS = int(sys.argv[1]) if len(sys.argv) > 1 else 48
26
+ _FLAGS = {a for a in sys.argv[1:] if a.startswith("--")}
27
+ _POSITIONAL = [a for a in sys.argv[1:] if not a.startswith("--")]
28
+ HOURS = int(_POSITIONAL[0]) if _POSITIONAL else 48
29
+ SKIP_VISITORS = "--skip-visitors" in _FLAGS
30
+ SKIP_SIGNUPS = "--skip-signups" in _FLAGS
24
31
  # App identity in Postgres is keyed by (userSlug, appSlug) — filtering on appSlug
25
32
  # alone would aggregate dev/remix/test twins under other handles. OWNER scopes it
26
33
  # to the one owner whose /vibe/<owner>/<slug> path the CF_PATH also targets.
@@ -38,9 +45,46 @@ since_iso = since.strftime("%Y-%m-%dT%H:%M:%SZ")
38
45
  now_iso = now.strftime("%Y-%m-%dT%H:%M:%SZ")
39
46
  since_ms = int(since.timestamp() * 1000)
40
47
 
48
+ def load_dev_vars():
49
+ """Mirror loadDevVars() in usage-report-util.ts: api/svc/.dev.vars is a
50
+ supported source for these keys, so the TS tools, check-env.sh and this
51
+ script must all agree on what 'set' means. First occurrence wins, quotes
52
+ are stripped, and a real environment variable always takes precedence."""
53
+ for path in (os.path.join(DB_DIR, ".dev.vars"), ".dev.vars"):
54
+ if not os.path.exists(path):
55
+ continue
56
+ with open(path, encoding="utf8") as fh:
57
+ for raw in fh:
58
+ line = raw.strip()
59
+ if not line or line.startswith("#") or "=" not in line:
60
+ continue
61
+ key, _, value = line.partition("=")
62
+ key, value = key.strip(), value.strip()
63
+ if len(value) >= 2 and value[0] == value[-1] and value[0] in "\"'":
64
+ value = value[1:-1]
65
+ os.environ.setdefault(key, value)
66
+
67
+
68
+ load_dev_vars()
41
69
  CF_TOKEN = os.environ.get("CLOUDFLARE_API_TOKEN")
42
70
  CLERK_KEY = os.environ.get("CLERK_SECRET_KEY")
43
71
 
72
+ # A missing key must not silently zero a leg of the funnel. Without CF_TOKEN the
73
+ # requests go out as "Bearer None", the HTTPError is swallowed, the counters stay
74
+ # at their zero initialisers, and the last line reads "FUNNEL: ~0 visits" — a
75
+ # plausible number about a dead app rather than a visible failure. Fail closed;
76
+ # --skip-visitors / --skip-signups opt out explicitly and stamp the funnel.
77
+ _missing = []
78
+ if not CF_TOKEN and not SKIP_VISITORS:
79
+ _missing.append("CLOUDFLARE_API_TOKEN (visitor traffic; without it the funnel would read ~0 visits)")
80
+ if not CLERK_KEY and not SKIP_SIGNUPS:
81
+ _missing.append("CLERK_SECRET_KEY (sign-ups; without it the funnel would read 0 sign-ups)")
82
+ if _missing:
83
+ print("refusing to run — missing credentials:\n " + "\n ".join(_missing), file=sys.stderr)
84
+ print("\ncheck your env: usage-report/check-env.sh --tool vibe-usage"
85
+ "\nor accept a partial funnel with --skip-visitors / --skip-signups", file=sys.stderr)
86
+ sys.exit(2)
87
+
44
88
 
45
89
  def db(sql):
46
90
  """Run a read-only query via db:inspect, return parsed rows."""
@@ -109,63 +153,83 @@ print(f" writers new-to-app={split['new']} returning={split['returning']}")
109
153
  # ---- 2. Cloudflare: read-only visitors (day-sliced; zone caps at 1d) ------
110
154
  print("\nTRAFFIC (all visitors, incl. non-signed-in; sampled + IP counts overlap days)")
111
155
  tot_ip = tot_visits = tot_req = 0
112
- slice_start = since
113
- while slice_start < now:
114
- slice_end = min(slice_start + timedelta(hours=24), now)
115
- q = f'''query {{ viewer {{ zones(filter: {{zoneTag: "{CF_ZONE}"}}) {{
116
- httpRequestsAdaptiveGroups(limit: 5000, filter: {{
117
- datetime_geq: "{slice_start.strftime('%Y-%m-%dT%H:%M:%SZ')}",
118
- datetime_leq: "{slice_end.strftime('%Y-%m-%dT%H:%M:%SZ')}",
119
- clientRequestPath_like: "{CF_PATH}"}}) {{
120
- dimensions {{ clientIP }} sum {{ visits }} count }} }} }} }}'''
121
- res = cf_graphql(q)
122
- if res.get("errors") or res.get("_error"):
123
- print(f" [{slice_start:%m-%d %H:%M}] cf error: {res.get('errors') or res.get('_error')}")
124
- else:
125
- rows = res["data"]["viewer"]["zones"][0]["httpRequestsAdaptiveGroups"]
126
- ips = len(rows); v = sum(r["sum"]["visits"] for r in rows); c = sum(r["count"] for r in rows)
127
- tot_ip += ips; tot_visits += v; tot_req += c
128
- print(f" [{slice_start:%m-%d %H:%M}→{slice_end:%H:%M}] IPs={ips} visits={v} requests={c}")
129
- slice_start = slice_end
130
- print(f" TOTAL: IPs={tot_ip} (summed per-slice — cross-day overlap, not exact uniques)"
131
- f" visits={tot_visits} requests={tot_req}")
156
+ cf_failed = False
157
+ if SKIP_VISITORS:
158
+ print(" SKIPPED (--skip-visitors) — Cloudflare was never queried. The zeros below mean")
159
+ print(" 'not measured', not 'no traffic'.")
160
+ else:
161
+ slice_start = since
162
+ while slice_start < now:
163
+ slice_end = min(slice_start + timedelta(hours=24), now)
164
+ q = f'''query {{ viewer {{ zones(filter: {{zoneTag: "{CF_ZONE}"}}) {{
165
+ httpRequestsAdaptiveGroups(limit: 5000, filter: {{
166
+ datetime_geq: "{slice_start.strftime('%Y-%m-%dT%H:%M:%SZ')}",
167
+ datetime_leq: "{slice_end.strftime('%Y-%m-%dT%H:%M:%SZ')}",
168
+ clientRequestPath_like: "{CF_PATH}"}}) {{
169
+ dimensions {{ clientIP }} sum {{ visits }} count }} }} }} }}'''
170
+ res = cf_graphql(q)
171
+ if res.get("errors") or res.get("_error"):
172
+ cf_failed = True
173
+ print(f" [{slice_start:%m-%d %H:%M}] cf error: {res.get('errors') or res.get('_error')}")
174
+ else:
175
+ rows = res["data"]["viewer"]["zones"][0]["httpRequestsAdaptiveGroups"]
176
+ ips = len(rows); v = sum(r["sum"]["visits"] for r in rows); c = sum(r["count"] for r in rows)
177
+ tot_ip += ips; tot_visits += v; tot_req += c
178
+ print(f" [{slice_start:%m-%d %H:%M}→{slice_end:%H:%M}] IPs={ips} visits={v} requests={c}")
179
+ slice_start = slice_end
180
+ print(f" TOTAL: IPs={tot_ip} (summed per-slice — cross-day overlap, not exact uniques)"
181
+ f" visits={tot_visits} requests={tot_req}")
182
+ # A slice that errored contributes 0, so a partly-failed run must not present
183
+ # its total as a measurement.
184
+ if cf_failed:
185
+ print(" ⚠ at least one slice errored — the total above is a FLOOR, not a count.")
132
186
 
133
187
  # ---- 3. Clerk: sign-ups + baseline ---------------------------------------
134
188
  print("\nSIGN-UPS (Clerk, platform-wide)")
135
- total = clerk("/users/count").get("total_count", "?")
136
- active = clerk(f"/users/count?last_active_at_since={since_ms}").get("total_count", "?")
137
- # Page back until we pass the baseline window's start, else the newest 200 would
138
- # silently cap `new`/`prior` during exactly the spike/long-window runs this targets.
139
- base_start = since_ms - 14 * 86400000
140
- users, offset, capped = [], 0, False
141
- while True:
142
- page = clerk(f"/users?order_by=-created_at&limit=500&offset={offset}")
143
- if not isinstance(page, list) or not page:
144
- break
145
- users += page
146
- if page[-1]["created_at"] < base_start: # covered the whole window+baseline
147
- break
148
- offset += 500
149
- if offset >= 5000: # 10k-account safety stop
150
- capped = True
151
- break
152
- new = [u for u in users if u["created_at"] >= since_ms]
153
- prior = [u for u in users if base_start <= u["created_at"] < since_ms]
154
- base_per = len(prior) / (14 / (HOURS / 24))
155
- print(f" total accounts(cumulative)={total} active-in-window={active}")
156
- cap_note = " ⚠ paging capped at 10k new/baseline may undercount" if capped else ""
157
- print(f" new sign-ups={len(new)} (prior baseline ≈{base_per:.1f} per {HOURS}h){cap_note}")
158
- doms = {}
159
- for u in new:
160
- d = (u["email_addresses"][0]["email_address"].split("@")[-1]
161
- if u.get("email_addresses") else "?")
162
- doms[d] = doms.get(d, 0) + 1
163
- if doms:
164
- print(" domains: " + ", ".join(f"{k}={v}" for k, v in sorted(doms.items(), key=lambda x: -x[1])))
189
+ if SKIP_SIGNUPS:
190
+ print(" SKIPPED (--skip-signups) — Clerk was never queried; sign-ups are UNKNOWN, not 0.")
191
+ new = []
192
+ else:
193
+ total = clerk("/users/count").get("total_count", "?")
194
+ active = clerk(f"/users/count?last_active_at_since={since_ms}").get("total_count", "?")
195
+ # Page back until we pass the baseline window's start, else the newest 200 would
196
+ # silently cap `new`/`prior` during exactly the spike/long-window runs this targets.
197
+ base_start = since_ms - 14 * 86400000
198
+ users, offset, capped = [], 0, False
199
+ while True:
200
+ page = clerk(f"/users?order_by=-created_at&limit=500&offset={offset}")
201
+ if not isinstance(page, list) or not page:
202
+ break
203
+ users += page
204
+ if page[-1]["created_at"] < base_start: # covered the whole window+baseline
205
+ break
206
+ offset += 500
207
+ if offset >= 5000: # 10k-account safety stop
208
+ capped = True
209
+ break
210
+ new = [u for u in users if u["created_at"] >= since_ms]
211
+ prior = [u for u in users if base_start <= u["created_at"] < since_ms]
212
+ base_per = len(prior) / (14 / (HOURS / 24))
213
+ print(f" total accounts(cumulative)={total} active-in-window={active}")
214
+ cap_note = " ⚠ paging capped at 10k — new/baseline may undercount" if capped else ""
215
+ print(f" new sign-ups={len(new)} (prior baseline ≈{base_per:.1f} per {HOURS}h){cap_note}")
216
+ doms = {}
217
+ for u in new:
218
+ d = (u["email_addresses"][0]["email_address"].split("@")[-1]
219
+ if u.get("email_addresses") else "?")
220
+ doms[d] = doms.get(d, 0) + 1
221
+ if doms:
222
+ print(" domains: " + ", ".join(f"{k}={v}" for k, v in sorted(doms.items(), key=lambda x: -x[1])))
165
223
 
166
224
  # funnel cross-ref: which new Clerk accounts wrote in the app
167
225
  writers = {r["userId"] for r in db(f'''SELECT DISTINCT "userId" FROM "AppDocuments"
168
226
  WHERE {APP_FILTER} AND created >= '{since_iso}' ''')}
169
227
  new_ids = {u["id"] for u in new}
170
- print(f"\nFUNNEL: ~{tot_visits} visits {len(new)} sign-ups → "
171
- f"{len(writers)} active writers ({len(writers & new_ids)} of them brand-new accounts)")
228
+ visits_txt = "UNKNOWN" if SKIP_VISITORS else (f"~{tot_visits}+" if cf_failed else f"~{tot_visits}")
229
+ signups_txt = "UNKNOWN" if SKIP_SIGNUPS else str(len(new))
230
+ # The cross-reference is derived from `new`, so skipping Clerk makes it
231
+ # unmeasured too — printing "0 of them brand-new" would be the same
232
+ # plausible-negative this whole change exists to remove.
233
+ new_txt = "UNKNOWN" if SKIP_SIGNUPS else str(len(writers & new_ids))
234
+ print(f"\nFUNNEL: {visits_txt} visits → {signups_txt} sign-ups → "
235
+ f"{len(writers)} active writers ({new_txt} of them brand-new accounts)")