Last Updated: 2026-09-05 · Status: Active
What's built is in implementation-plan.md. This is what isn't.
Deploy-time work owed
These are not code changes — they're steps someone has to take before the built code does anything.
| # | What | Why it's blocking |
|---|---|---|
| D1 | wrangler.toml is gitignored repo-wide (9 workers). Engagement's COLLECTIONS_SERVICE and SITE_SYNC bindings, and collections' secret documentation, are local-only. |
The bindings must be re-applied on whatever machine deploys. |
| D2 | Set ENGAGEMENT_INTERNAL_TOKEN on collections-service to engagement's existing value. |
entry: targets fail open (accepted but unverified) until this exists. |
| D3 | SITE_SYNC_INTERNAL_TOKEN and PLATFORM_ADMIN_TOKEN on engagement; PLATFORM_ADMIN_TOKEN + an ENGAGEMENT_SERVICE binding on internal-api. |
Site-sync integration and the blocklist are code-complete but not live until that redeploy ships. |
| D4 | Set CF_ACCOUNT_ID (done) and CF_AE_TOKEN (Account Analytics:Read — still unset as of 2026-09-09). |
The Sources panel shows "not available"; everything else works. |
| D5 | eng_members) and 0005 (eng_platform_blocklist). |
|
| D6 | Merge the changesets "Version Packages" PR to publish @vlozi/blog@2.2.0, then bump apps/website and set a real NEXT_PUBLIC_ENGAGE_SITE_ID. |
vlozi.app can't dogfood until then. |
| D7 | Users must re-login for Engagement to appear in their sidebar. | JWTs carry the service list. |
Known gaps
No edge cache in front of /e/*. The plan's Phase 1 called for cachedPublicProxy (B12/B35) with per-route TTLs at the gateway. It was never built; engagement.proxy.ts is a plain forward. The worker's Cache-Control headers are honoured by browsers only, so every distinct visitor's page load hits the worker for /summary. Fine at current scale; the first thing to build when it isn't. (Found by the final audit — the docs had claimed edge caching that didn't exist; corrected.)
Comment IPs are stored raw, not hashed. eng_comments.source_ip is the actual address, because a tenant's ban-by-IP and the platform blocklist's ip_hash kind both compare against it verbatim (the kind's name is a misnomer). Hashing would need every comparison point to hash too. The 30-day purge (/cron/purge-comment-ips) now exists and bounds the exposure; hashing is a follow-up decision. The purge cron needs scheduling alongside send-digests and weekly-summary — same 5-cron blocker.
Digest and weekly-summary crons need scheduling. /cron/send-digests and /cron/weekly-summary exist and are tested, but nothing calls them on a schedule yet. Cloudflare's 5-cron account limit is already reached (see the flows-service memory note), so this needs either a slot freed or billing-crons' DO to fan them out.
Load test has never been run. scripts/load-test.mjs is written and refuses to run against production. The 10k-beacons/minute claim is untested against a real deployment, and the batching half of it can only be confirmed from worker logs afterwards.
entry: targets have no dashboard drawer detail. The Content table filters by type and shows entries, but the drawer's series view was built around posts. Entries render, they just don't get the same context.
Deliberately not doing
| Why | |
|---|---|
| Hosted blog | Dropped 2026-09-04; site-sync covers publish-to-live. |
| Reader profiles / follows / a social graph | A member exists to prove control of an email address. Every field beyond that is one we'd have to protect, export and delete. |
| Nested replies beyond one level | Deep threads need collapse UI, "load more", and moderation of subtrees. One level covers the actual use case (an owner answering a reader). |
| Rating markup on articles | Self-serving review markup. productRatingJsonLd exists for the Product case that isn't. |
| DO sharding on by default | Splits the dedup set, so uniques inflate. Implemented and off — see lib/counter-shard.ts. |
| Reactions in the DO | They need read-before-write and immediate visibility. Batching them would buy nothing and cost correctness. |
Follow-ups from the platform audit (Phase 14)
Tracked in the implementation plan §2 bug table. Not engagement bugs — things engagement's audit surfaced elsewhere:
- B2 forms' lenient origin check on writes (engagement uses strict from day one; forms should adopt it)
- B7 the two seed files disagree on service names, limits and addons
- B8
rebuildEntitlementsskips services with no plan-limit rows — collections and flows were never backfilled - B15 the
enabled && !userDisabledrule exists in three helpers and five inline copies - B16 chat-engine still emits the legacy
widget.logicspike.comhost - B19 four pairs of wrangler
[dev] portcollisions - B26 forms'
.dev.varslacksCORE_DATABASE_URL, so local dev runs unbilled silently - B27 a hardcoded
content-engine → contentbreadcrumb special case - B28 blog-sdk's README hardcodes sizes and test counts that drift
- B29
competitive-audit.mdis an empty checklist - B31
?api_key=in query strings lands in logs; redact it at the gateway