Skip to content

feat(digest): on-demand weekly distribution-metrics CLI under PII invariants#41

Merged
SoapyRED merged 1 commit into
mainfrom
feat/digest-distribution-metrics
May 16, 2026
Merged

feat(digest): on-demand weekly distribution-metrics CLI under PII invariants#41
SoapyRED merged 1 commit into
mainfrom
feat/digest-distribution-metrics

Conversation

@SoapyRED
Copy link
Copy Markdown
Owner

Summary

Rebuilds the weekly digest that was killed on 2026-05-06 (commit 569cdfc: "privacy hardening, low-signal feature") under a strict spec confirmed in conversation. Hard invariants encoded in CLAUDE.md FAULT 14 + scripts/weekly-digest/README.md verbatim + pii-filter.mjs at runtime + test.mjs at PR time.

Six invariants (all enforced)

  1. On-demand only. npm run digest. No workflow, no cron, no email.
  2. Output to stdout or scripts/weekly-digest/output/ (gitignored). Never to a tracked file. git check-ignore verified.
  3. PII filter — zero tolerance. Email pattern OR cus_* / sub_* Stripe ID in the assembled output → script throws.
  4. Stripe = aggregates only. No /v1/customers. No customer-object expansion. Permitted out of any Stripe response: amount, currency, status, items.data[].price.{unit_amount, recurring}, items.data[].quantity, created, canceled_at. Everything else dropped inside the module before the result leaves.
  5. Honest empty state. All sources hasMovement: false → print No movement this week and exit. No filler.
  6. Kill-switch. SCRIPTS_WEEKLY_DIGEST=enabled in .env.local; unset → exit 0 with one-line message.

Sources (closed scope without explicit approval)

Source Module Auth Behaviour without key
npm freightutils-mcp npm-downloads.mjs none n/a — public
GitHub SoapyRED/{freighttools,freightutils-mcp} github-stats.mjs GITHUB_TOKEN optional unauthenticated 60/hr
Smithery @freightutils/freightutils-mcp smithery-stats.mjs SMITHERY_API_KEY required section renders as manual-check with listing URL
Stripe aggregates stripe-aggregates.mjs STRIPE_SECRET_KEY required section renders as not-configured

Test results (npm run digest:test)

15 assertions PASS — pii-filter behaves on positive + negative cases; every section runs with PII-laden fixture payloads (emails in GitHub repo owner, cus_* / sub_* IDs in Stripe responses, receipt_email on charges); assembled output contains zero leaked PII; empty-state path also covered.

✓ pii-filter clean on clean text
✓ pii-filter caught email: leaked.user@example.com
✓ assertNoPii throws on email
✓ pii-filter caught cus_ id: cus_FixtureLeakageDeadbeef00
✓ assertNoPii throws on cus_ id
✓ pii-filter caught sub_ id: sub_FixtureLeakageDeadbeef00
✓ assertNoPii throws on sub_ id
✓ stripe active-count populated from fixture
✓ stripe gross-volume populated from fixture
✓ npm / github / smithery sections populated
✓ digest output is PII-free despite fixture injections
✓ assertNoPii on full output: no throw
✓ empty-state prints "No movement this week."

npm run digest with kill-switch unset → exits 0 with the expected one-line message.

FAULT 5 application

Item Status
CHANGELOG.md entry SKIPPED — see note below
/changelog renders n/a
withAuditRest on new routes n/a (no API routes)
generateMetadata on new pages n/a (no pages)
sitemap.ts updated n/a
openapi.json updated n/a
nav / footer / Postman / npm-mcp / README n/a
tsc clean ✓ (exit 0)
lint:audit / lint:api-casing / lint:seo-titles ✓ all PASS

Why no public CHANGELOG entry. This PR has zero user-visible changes — it's an internal dev-only CLI invoked from one developer's machine. The FAULT 5 rule wording is "CHANGELOG.md entry added describing this PR's user-visible changes". Publishing "we monitor Stripe / npm / GitHub / Smithery weekly" on the public changelog would also leak signal we don't need to give out. The CLAUDE.md FAULT 14 paragraph is the durable record for future Claude Code sessions — that's where the invariants live.

Test plan (post-merge)

  • Vercel preview READY (Vercel will build but there are no app-surface changes; build should be a no-op pass)
  • Post-merge: 10-path Sentry-quiet sweep (existing routes still 200; no new surface to test)

🤖 Generated with Claude Code

…ariants

Rebuilds the weekly digest that was killed on 2026-05-06 (commit 569cdfc:
"privacy hardening, low-signal feature"), under a tighter spec confirmed
in conversation:

- ON-DEMAND ONLY. `npm run digest`. No workflow file, no cron, no Resend
  email. Reinstating cadence requires a fresh sprint with a privacy review.
- OUTPUT TO STDOUT. Or to scripts/weekly-digest/output/ (gitignored —
  `git check-ignore` verified). NEVER to a tracked file in the repo.
- KILL-SWITCH. index.mjs reads SCRIPTS_WEEKLY_DIGEST from .env.local; if
  not "enabled", exits cleanly with a one-line message. Mothballing
  without deleting is a one-character env change.
- PII FILTER (keystone). pii-filter.mjs runs over the assembled output
  before stdout; any email pattern or `cus_*` / `sub_*` Stripe ID throws.
- AGGREGATE-ONLY STRIPE. stripe-aggregates.mjs lists subscriptions +
  charges, accumulates ONLY {amount, currency, status, price recurring
  metadata, quantity, created, canceled_at} and discards every other
  field. No /v1/customers calls. No customer-object expansion.
- HONEST EMPTY STATE. If every source reports hasMovement=false, prints
  "No movement this week" and exits. No filler narrative.
- CLOSED SCOPE. npm freightutils-mcp + GitHub (SoapyRED/freighttools +
  SoapyRED/freightutils-mcp) + Smithery (API only — never scrape) +
  Stripe aggregates. New sources require explicit approval.

Files:
- CLAUDE.md — new FAULT 14 "Weekly-digest PII invariant" hard rule (6
  invariants, mirrors scripts/weekly-digest/README.md verbatim).
- .gitignore — adds scripts/weekly-digest/output/.
- scripts/weekly-digest/{README, pii-filter, npm-downloads, github-stats,
  smithery-stats, stripe-aggregates, index, test}.mjs.
- package.json — `npm run digest` + `npm run digest:test`.

`npm run digest:test` PASSES (15 assertions): pii-filter behaves
correctly on positive + negative cases; every section runs with PII-laden
fixture payloads injected (emails in GitHub repo owner, cus_/sub_ IDs in
Stripe responses, receipt_email on charges), and the assembled output
contains zero leaked PII. Empty-state path also covered.

`npm run digest` with kill-switch unset exits 0 with the expected
one-line message. tsc clean. lint:audit / lint:api-casing /
lint:seo-titles all pass.

FAULT 5 application: no public CHANGELOG entry. This is an internal
dev-only CLI with no UI, no API, no public surface — the FAULT 5 rule
wording is "user-visible changes". Announcing which platforms we monitor
would also be a small intentional-signal leak. The CLAUDE.md FAULT 14
paragraph is the durable record for future Claude Code sessions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented May 16, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
freighttools Ready Ready Preview, Comment May 16, 2026 9:24am

Request Review

@SoapyRED SoapyRED merged commit 1f67dca into main May 16, 2026
2 checks passed
@SoapyRED SoapyRED deleted the feat/digest-distribution-metrics branch May 16, 2026 09:24
SoapyRED added a commit that referenced this pull request May 16, 2026
Bumps Last-updated 9 May → 16 May. Captures the 17 PRs landed across
2026-05-13..2026-05-16 (PR #25 through PR #41) plus the 14 May infra
changes that didn't have their own PR (Cloudflare disconnect, Upstash
PAYG, IndexNow live).

Sections refreshed:
- Sprint cadence 13–16 May (new): full PR list with one-liner per PR.
- Platform: MCP v2.1.0 → v2.1.1; route count 36 → 38.
- Infrastructure changes (new): CF Workers disconnected 14 May, CF DNS-
  only / Vercel firewall is sole edge security, Upstash PAYG $20 cap,
  CLAUDE.md at root encodes FAULT 5 + FAULT 14, IndexNow workflow live.
- Data integrity status (new): table for ULD / Airlines / ADR / Containers
  / UN-LOCODE / HS / Vehicles / Customs-duty. ULD + Airlines + ADR
  verified: true; the other 5 verified: false pending allowlist
  extension (specific domains enumerated).
- Scraper defence status (new): PR #31 / #32 / #33 / #38 live, Phases
  3+4 deferred to runbook, Phase 2 skipped.
- Edge firewall: scoped to Vercel-only (CF inert now).
- Distribution surfaces: table with current download counts, Smithery
  score, MCP Registry STALE flag, Glama description STALE flag.
- Weekly digest CLI (new): six FAULT 14 invariants summarised; points
  at scripts/weekly-digest/README.md for the full spec.
- Vercel Analytics: 30-day baseline updated (3,311 visitors / 6,070
  PV / 69% bounce / SG 73%).
- First validated user signals: Tom (CEVA) preserved + Simon's team
  organic adoption added per 16 May report.
- What's blocked / What's next / Red flags: updated to reflect today's
  reality — vehicles+customs SHIPPED (#39 #40), weekly digest SHIPPED
  (#41), Make.com Town Hall 21 May 4PM BST queued, CEVA→WFS transition
  complete with week 2 of induction pending.
- Canonical references: added pointers to scripts/weekly-digest/ and
  the IndexNow workflow.

No CHANGELOG entry — internal doc, not user-visible. Per the prompt.

Co-authored-by: SoapyRED <soapyred@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant