Gates are named R1 to R10 so they cannot be confused with the gap-log IDs (G1 to G70, in gap-log.md).
Fill in Done on / by / evidence as each gate is met. Evidence is a file under evidence/ (see
evidence-checklist.md) or a link.
Check the AWS account first. The aws commands below must run against the SES account: the one signed in as founder@vlozi.app, where vlozi.app is a verified
identity in Mumbai. On 2026-10-07 the CLI on the development machine was signed into a different account (829547187034) that has no SES identities, configuration sets
or SNS topics, so its output says nothing about Vlozi (gap-log G77). Run aws sts get-caller-identity --query Account --output text before any command here, or use
the console equivalents (the identity's Authentication tab, the SES account dashboard, and Suppression list → account-level settings).
Commands are PowerShell. DNS checks are read-only and safe to run any time. Run wrangler commands from the app's folder with
$env:CLOUDFLARE_ACCOUNT_ID = "72fe41e9f39ad60cfb6937bb26ab50c3" set, or wrangler may use a cached wrong account.
R1 — Operator identity published
The case, the policies and the website must all name the same operator and the same address. The site reads them from
apps/website/lib/legal.ts.
- Operator decided (2026-10-07): Dipanshu Vishwakarma, trading as Vlozi. An individual; the business is not registered, so nothing may imply a company
- Address decided and spelling confirmed (2026-10-07, public): Devgaon, Azamgarh, Uttar Pradesh 276201, India. Spelled "Deogaon" until 2026-10-26, when it changed to the Aadhaar spelling so the site, the AWS account and AWS's identity verification agree (website redeployed the same day, Pages
904557f5, commit42c92e40on main) - Both appear in Terms, Privacy, Acceptable Use, Anti-Spam, Abuse and the site footer. Deployed 2026-10-07 and checked on the live pages the same day
- The Vlozi workspace's own organisation address (Newsletter settings, Footer) is set to the same address. It needs the owner's OK before it is written through the comms sender-settings tool (gap-log G63)
Done on / by / evidence: ______
R2 — AWS account in good standing
- Valid payment method on file: UPI AutoPay, set as default, AutoPay on (checked 2026-10-26, Billing → Payment preferences)
- Account contact details match the operator (Account → Contact information, 2026-10-26: the operator's name and the full address as the Aadhaar prints it; the website shows the short form, Devgaon, Azamgarh, Uttar Pradesh 276201). The billing address under Payment preferences still showed an older, misspelt form of the same area on 2026-10-26 and could not be edited there; re-check it in a day
- Root user MFA enabled (already on, checked 2026-10-26)
- Support plan confirmed in the console (Support → Your plan): Basic Support (2026-10-26). Enough to submit; Developer is only needed to open a technical case after a denial
- Alternate contacts (billing, operations, security) set to your existing private inbox, which does not depend on vlozi.app being up (set 2026-10-26; decided 2026-10-07, gap-log G56, G63)
- AWS confirms the account is fully verified (gap-log G79). On 2026-10-26 CloudShell would not start ("Your account verification is in progress"), and an AWS Health event "AWS ACCOUNT CUSTOMER VERIFICATION REQUIRED" (India customer verification) had opened that day. Billing → Account → Customer verification showed the name verified but the address unverified since 2026-07-04: the address typed in July did not match the Aadhaar. Fixed 2026-10-26: the account contact address was set to the Aadhaar wording and Aadhaar was verified through DigiLocker; name and address both Verified (20:42 IST). The address itself is deliberately not written here
- The AWS root address
founder@vlozi.appreceives a test mail from an outside account. A Cloudflare rule delivers it to a personal inbox, and AWS replies to the case arrive there
Done on / by / evidence: ______
R3 — Domain authentication
DKIM
aws sesv2 get-email-identity --region ap-south-1 --email-identity vlozi.app --query "DkimAttributes.[Status,CurrentSigningKeyLength,SigningAttributesOrigin]"- Status is
SUCCESS; note the key length and origin (the case text says nothing about key length unless this shows 2048). 2026-10-26, SES console: DKIM configuration Successful, signatures enabled, Easy DKIM, current and next signing lengthRSA_2048_BIT. So "2048-bit DKIM" is true
Custom MAIL FROM (SPF alignment)
aws sesv2 get-email-identity --region ap-south-1 --email-identity vlozi.app --query "MailFromAttributes"
Resolve-DnsName bounce.vlozi.app -Type MX
Resolve-DnsName bounce.vlozi.app -Type TXT-
MailFromDomainisbounce.vlozi.appandMailFromDomainStatusisSUCCESS(set 2026-10-26 with "Use default MAIL FROM domain" on MX failure; Successful in the SES console about 30 minutes after the records went live, 2026-10-26) - MX is
10 feedback-smtp.ap-south-1.amazonses.com(live on 1.1.1.1 and 8.8.8.8, 2026-10-26) - TXT is
v=spf1 include:amazonses.com ~all(live on 1.1.1.1 and 8.8.8.8, 2026-10-26)
DMARC
Resolve-DnsName _dmarc.vlozi.app -Type TXT- A record exists with reports (today:
p=nonewith Cloudflare's report address) and a week of the digest has been read: SES and Resend both pass. 2026-10-26, Cloudflare DMARC Management, last 30 days: 7 emails reported, 7 DMARC pass, 0 fail; "Amazon.com, Inc." 6 (100% DMARC, SPF aligned and DKIM aligned; Resend sends through Amazon, so its mail is in this row) and "Cloudflare, Inc." 1 (100%). Low volume, sop=nonestays for now - Optional:
p=quarantine; pct=25for a few clean days, thenpct=100, withadkim=r; aspf=rand the Cloudflareruakept. The case text names whatever DNS shows that day, so this is not required - A received message's headers (Gmail "Show original") show SPF pass, DKIM pass, DMARC pass, and the SPF line names
bounce.vlozi.app. Use a message SES sent (the comms log showsprovider: ses); a message that failed over to Resend proves nothing here
Done on / by / evidence: ______
R4 — Abuse and postmaster mailboxes work
Which addresses, and why, is decided in contact-addresses.md. As of 2026-10-06 they are mailboxes on vlozi.app in
Vlozi's own workspace (the workspace that holds the verified vlozi.app domain). The comms worker receives <name>@vlozi.app and delivers it
into the account on that address; replies leave from the same address through Resend. They are not Cloudflare rules. Mail to an
address nobody claimed bounces (since 2026-10-21, gap-log G11), but a failed lookup still loses mail silently, so each address needs a real
test, not an assumption.
-
abuse@vlozi.app: test mail from an outside address appeared in the mailbox on 2026-10-26 (owner's personal Gmail; filed under the abuse mailbox) -
postmaster@vlozi.app: appeared on 2026-10-26 (same Gmail; filed under the postmaster mailbox) -
security@vlozi.app: appeared on ______ -
hello@vlozi.app: appeared on ______. Decided 2026-10-07 (gap-log G55): the Cloudflare rule stays, so this address is received in the operator's personal inbox, not the Mailbox. Tick this when the outside test mail arrives there, and write that here -
privacy@vlozi.app: appeared on ______ -
legal@vlozi.app: appeared on ______ -
ops@vlozi.app(private; vendor contact): appeared on ______ - A reply sent from the dashboard from one of them reached the outside account, From
<name>@vlozi.app(2026-10-26: reply fromabuse@vlozi.app, shown Delivered in the dashboard)
Evidence so far (2026-10-06; platform-sent tests, not an outside account): ten mailboxes exist. A test to each of abuse, postmaster, privacy,
security, ops, legal, support, billing and info was seen arriving at the comms worker and filed by the Mailbox (worker logs). hello@ did not reach
the worker (G55). A reply from a Vlozi mailbox to an outside Gmail address arrived with From and Reply-To set to that mailbox, signed by vlozi.app.
Also on 2026-10-07 at 07:44 UTC the comms log records a reply sent from a Vlozi mailbox to the owner's Gmail (source mailbox, provider resend, delivery
status delivered), which means a mail from that Gmail reached a role mailbox and a reply came back; which address it was has not been written down. The boxes above
stay unticked until the outside-account test has been run for each address.
Done on / by / evidence: ______
R5 — Bounce and complaint pipeline proven
Use the platform's own mail. A direct aws sesv2 send-email call writes no log row, so no suppression row can appear, and tenant mail
never reaches SES (R6). In the Vlozi workspace, open Team → Invite, invite each address below, then revoke the invitations. Each invitation counts toward the
5-per-recipient-per-day limit and holds a seat while it is pending.
| Invite | Expected |
|---|---|
success@simulator.amazonses.com |
Delivery event reaches comms |
bounce@simulator.amazonses.com |
Bounce event, suppression row written, a second invitation to it is blocked |
complaint@simulator.amazonses.com |
Complaint event, suppression row written |
suppressionlist@simulator.amazonses.com |
account-level suppression bounce handled |
- The comms log shows
provider: sesfor each send, and each result is visible in the logs or the ops "Email suppression" page (screenshots). 2026-10-26, invitations from the Vlozi workspace, watched withwrangler tailon comms: every simulator send went through SES ((ses)message ids);success@recorded sent then delivered,bounce@bounced,complaint@complained,suppressionlist@bounced, and a second invitation tobounce@was refused before sending ("AUTH MAIL SUPPRESSED … (hard_bounce)"). For contrast, the same invitation to the owner's unverified Gmail was refused by the SES sandbox ("Email address is not verified") and delivered by the Resend fallback, as designed - The SNS subscription shows a real ARN (confirmed): the delivery, bounce and complaint events above arrived from AWS and were accepted (2026-10-26)
- The webhook rejects an unsigned POST:
curl.exe -i -X POST https://api.vlozi.app/comms/v1/webhooks/ses -H "Content-Type: application/json" -d "{}"returns a 4xx (401, 2026-10-26) -
aws sesv2 get-account --region ap-south-1 --query "SuppressionAttributes"recorded; note whether both BOUNCE and COMPLAINT are listed (the case text only says the account list is enabled if they are). 2026-10-26, SES console (Suppression list → Account-level settings): Enabled, reasons "Bounce and complaints", list empty. Our code never sets a configuration set's own suppression options, and the hand-madevlozi-platformset (all platform mail) shows "Use account level settings" (checked 2026-10-26). Its reputation metrics were "Not tracking" that day; the account-level metrics the alarms use are published regardless
Done on / by / evidence: ______
R6 — Declared-use guard shipped
SES carries platform mail only until the tenant-mail request is approved. Deployed 2026-10-06 (comms, newsletter-service, mailbox, forms-service). Deployed is not verified: the boxes below are the proof.
- comms, newsletter-service, mailbox and forms-service deployed together (2026-10-06)
-
SES_TENANT_SENDINGis not set on the comms worker:npx wrangler secret listfromapps\communication(names only), checked 2026-10-07 - A tenant send from a
mail.vlozi.appmailbox (a form notification, or a reply from a role mailbox on that domain) is refused 503TENANT_SENDING_NOT_ENABLED; the comms log shows it - A platform send to a verified recipient shows
provider: sesin the comms log. An unverified recipient fails over to Resend while SES is in the sandbox; that is expected - You accept the customer impact: while the guard is on, workspaces on
mail.vlozi.appcannot send campaigns, mailbox replies or form notifications (gap-log G22, G23). Mail fromvlozi.appgoes through Resend and still works
Done on / by / evidence: ______
R7 — Platform-mail abuse bounds shipped
Manager deployed 2026-10-06 (8284200f). Deployed is not verified: the 429 checks below have not been run. The two limits interfere, so use the
methods given.
- manager deployed (2026-10-06)
- Sign-up: the 6th request from one IP address within 15 minutes returns 429 (use made-up addresses; each attempt counts)
- Code resend: the 11th
verify-email/resendfrom one IP address within 15 minutes returns 429. Use a different made-up address each time: a repeat for one address hits the 60 s cooldown first, and an unknown address answers 200 but still counts toward the IP limit - Invitations: the 6th invitation to one address in a day returns 429, and a 4th resend of one invitation within an hour returns 429. Use your own address and revoke the invitations afterwards, because each takes a seat while pending. A workspace is also limited to 30 invitations an hour
- Email verification is required before a workspace can be created (already true:
onboarding.ts)
Done on / by / evidence: ______
R8 — Public site accurate, policies published
Every URL must return 200 and say what the case says. Policy text lives in apps/website/app/*/page.tsx; the long-form drafts are in
../../legal/.
Deployed 2026-10-07, by the owner. The live text was read the same day and matches the repository: operator and address, venue, refund and agency wording, the suppression and credit wording, and no old phrases. The sitemap lists the four new pages. The pre-flight below was meant to come first; two items were not done and are now overdue, because the live Abuse and Anti-spam pages promise them:
-
LEGAL_EFFECTIVEinapps/website/lib/legal.tsis the deploy date (the pages say 7 October 2026, gap-log G62) - The address spelling is confirmed (2026-10-07)
-
abuse@andpostmaster@pass the outside test (R4) and the un-consented list is gone (G17, G61). Both done 2026-10-26: the 502 imported contacts were deleted rather than revoked, and none had ever been mailed - The docs site (
handbook.vlozi.app) is behind a login. It is not: it answers without one (checked 2026-10-07), and it serves what is underdocs/, which includes the privateops@address and internal gap descriptions (gap-log G70)
To redeploy after a later change:
$env:CLOUDFLARE_ACCOUNT_ID = "72fe41e9f39ad60cfb6937bb26ab50c3"
cd apps\website
pnpm run build
npx wrangler pages deploy out --project-name=vlozi-website --branch=main --commit-dirty=true--branch=main is required, or the deploy is a preview. Status of the site itself:
- Terms, Privacy, Acceptable Use, Anti-Spam, Abuse and Sub-processors pages are live (checked 2026-10-07)
- The footer carries the operator line and the sitemap lists the new pages (checked 2026-10-07);
llms.txtis not checked - One sub-processor list, on its own page, linked from Privacy and Security
- Each page read once against the case text; nothing contradicts it
foreach ($p in 'terms','privacy','acceptable-use','anti-spam','abuse','sub-processors') { curl.exe -sI "https://vlozi.app/$p" | Select-Object -First 1 }Done on / by / evidence: ______
Site claims still open
Most of the original list (llms files, newsletter product copy, sub-processor list, analytics wording) was fixed and deployed on 2026-10-06 (Cloudflare Pages
79cc17b9). Two rows are not:
| Where | Claim | Status |
|---|---|---|
| Newsletter product page | "Real-time analytics: open rates, click maps ... no third-party pixel" | First-party open and click tracking is built, but its switch (TRACKING_EMIT) is off in production, so the claim is not true until you turn it on. Switch it on, or reword (gap-log G21) |
| Waitlist and early-access forms | "No spam" / "launch updates — no spam" | Not false by itself, but the waitlist is single opt-in. Never mail it without a confirmation step |
R9 — CloudWatch alarms
AWS console → CloudWatch → Alarms → Create → SES metrics.
-
Reputation.BounceRate: alarm at 4% (warning 2%), notifying an email you read. 2026-10-26:ses-bounce-rate-4pct, Average over 1 hour,>= 0.04, missing data treated as good, notifies SNS topicses-reputation-alerts. No warning-level alarm -
Reputation.ComplaintRate: alarm at 0.08% (warning 0.05%), notifying an email you read. 2026-10-26:ses-complaint-rate-0-08pct, threshold>= 0.001(0.1%), not 0.08%: the console's threshold box keeps three decimal places and turned0.0008into 0. 0.1% is where AWS starts reviewing an account (it pauses sending at 0.5%), so the alarm still fires well before a pause. Same topic and settings as the bounce alarm. The name still says 0-08pct; recreating the alarm only to rename it was not worth it - The alarm email is your existing private inbox, which does not depend on this platform being up (decided 2026-10-07, gap-log G63), and the SNS email subscription is confirmed (check the inbox). Topic created with the private inbox and the subscription confirmed by the owner, 2026-10-26
- Screenshot of both alarms in
OKstate (2026-10-26). The two rate metrics had no data yet (SES publishes them only after real sending; simulator mail does not count), so the alarms were created from the SES Reputation metrics page's "View in CloudWatch" link, not the metric picker. CloudShell refused to start that day: "Your account verification is in progress" (see R2)
Done on / by / evidence: ______
R10 — Case log
-
case-log.mdexists and lists the earlier attempts (two submitted and denied, one drafted and never sent), as far as they can be reconstructed - Every AWS message from now on is pasted verbatim with the case ID and date. This stays open until the case closes
Done on / by / evidence: file created 2026-10-05
Known gaps a reviewer could find
The full list, with owners, is in gap-log.md ("Open at a glance"). The two that matter for this request:
Vlozi's own newsletter list held 502 contacts who never opted in.Deleted 2026-10-26; none had ever been mailed. The list now holds only people who signed up themselves, plus three unsubscribe records (gap-log G17).- No content scanning, no tenant ban, no log-retention job. The Privacy page makes no promise that depends on them; they are Phase B items.
Before you press submit
- All ten gates above are green and dated
- Every bracketed tag in
case-message.mdis resolved or its sentence is deleted - The text matches the live site, the policies and the DNS today (re-run the R3 and R8 commands)
- The un-consented newsletter contacts were never mailed from any provider (checked 2026-10-26: 0 campaign sends) and are now deleted
- You know who answers the case and will check it daily for a week