Skip to content

fix(public): render the signup rejection signal on the homepage - #111

Merged
nish3451 merged 39 commits into
mainfrom
fix/signup-signal-error-banner
Aug 13, 2026
Merged

fix(public): render the signup rejection signal on the homepage#111
nish3451 merged 39 commits into
mainfrom
fix/signup-signal-error-banner

Conversation

@nish3451

@nish3451 nish3451 commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

What

The worker 303-redirects a rejected signup back to /?signal=invalid (its email regex is stricter than the browser's type=email check — 'a@b' passes client-side but not server-side), but no page code ever read that signal. A visitor whose email the server rejected was silently bounced to the homepage with zero feedback: no banner, no alert, no explanation, and their input gone.

Verified live (2026-08-11, real Chromium): submitting a@b -> 303 -> https://tinystudio.io/?signal=invalid renders with feedback: {msgs: [], hasBanner: false}.

Fix

  • public/index.html: a role=alert banner (#signal-invalid), hidden by default, sits under the hero sub-heading.
  • public/index.js: reads ?signal= on load; for a rejection signal it reveals the banner, moves focus into it for assistive tech, then strips the query with history.replaceState so a refresh or a copied link does not re-show the error.
  • public/index.css: banner styling using the existing --sig palette; .signal[hidden]{display:none} keeps it hidden until the handler reveals it (plain display:none would override the hidden attribute).
  • scripts/check-site.mjs: deterministic source guards — the banner markup (role=alert, starts hidden), the handler wiring (reads signal=, references signal-invalid, calls replaceState), the CSS, and the worker's htmlRedirect(url, invalid) redirect all must stay in place.
  • scripts/test-agent-worker.mjs: new test locking the contract — invalid email -> 303 -> /?signal=invalid, and no row persisted for the rejected signup.

Validation

  • npm test -> 93 tests, 0 fail (check 16/16, worker 56/56, headings 6/6, sitemap 7/7, contract 8/8, ui 16/16).
  • npm run check:render-blocking -> all six pages PASS under the production CSP.
  • git diff --check clean.
  • Real Chromium, local static copy: normal load hides the banner (hidden:true, display:none); ?signal=invalid reveals it (hidden:false, display:block, focus:true), strips the URL, and mobile 390x844 shows the banner in-viewport with zero overflow and no console errors.

Note: wrangler deploy --dry-run fails in this worktree with 'Unexpected end of file in JSON' on ../../../package.json — reproduced identically on clean origin/main in the same worktree layout (wrangler resolves the project root relative to the nested worktree path); the change touches no JSON and CI's shallow checkout does not hit it.

Summary by CodeRabbit

  • New Features

    • Added an accessible alert for invalid email addresses submitted through the signup form.
    • Invalid signup attempts now return visitors to the homepage with a clear notification.
  • Bug Fixes

    • Prevented rejected signup requests from being saved.
    • The invalid-signup message receives focus, and the temporary URL query is cleaned up automatically.
  • Tests

    • Added regression checks covering the alert, redirect behavior, and prevention of invalid data persistence.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@nish3451, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 59 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Free

Run ID: 3c745088-11cd-46f0-b307-ad61fb7ed696

📥 Commits

Reviewing files that changed from the base of the PR and between a6a5b12 and d3cb29a.

📒 Files selected for processing (2)
  • scripts/check-site.mjs
  • scripts/test-agent-worker.mjs
ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Free

Run ID: 2692b036-264b-491c-b709-37b732d947fc

📥 Commits

Reviewing files that changed from the base of the PR and between 8b2bcc7 and a6a5b12.

📒 Files selected for processing (1)
  • scripts/test-agent-worker.mjs
🚧 Files skipped from review as they are similar to previous changes (1)
  • scripts/test-agent-worker.mjs

📝 Walkthrough

Walkthrough

The signup flow now redirects invalid email submissions with ?signal=invalid. The homepage reveals and focuses an accessible alert, removes the query string, and adds styling. Static and worker tests verify the behavior.

Changes

Invalid signup signal

Layer / File(s) Summary
Alert rendering and URL handling
public/index.html, public/index.css, public/index.js
The homepage adds a hidden invalid-email alert. The client reveals and focuses it for signal=invalid, then removes the query string.
Rejection regression coverage
scripts/check-site.mjs, scripts/test-agent-worker.mjs
Static checks verify the alert, client handling, CSS state, and worker redirect. Worker tests verify the 303 redirect and absence of database persistence.

Estimated code review effort: 2 (Simple) | ~10 minutes

Mergeability Score: ⚪ Minimal · up to a6a5b

The change makes rejected signups show an accessible homepage message and cleans up the rejection URL; no actionable merge-blocking risk remains after normal checks and review.

Sequence Diagram(s)

sequenceDiagram
  participant SignupRequest
  participant AgentWorker
  participant Browser
  SignupRequest->>AgentWorker: Submit invalid email
  AgentWorker->>Browser: Redirect to /?signal=invalid
  Browser->>Browser: Read signal=invalid
  Browser->>Browser: Reveal and focus signal-invalid
  Browser->>Browser: Remove query string with history.replaceState
Loading

Note

🎁 Summarized by CodeRabbit Free

Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login.

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c87126d733

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread public/index.js
Comment on lines +30 to +31
var match=(location.search||'').match(/[?&]signal=([^&]+)/);
if(!match)return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Validate the signal value before showing rejection

The handler checks only that a nonempty signal parameter exists, so /?signal=saved or /?signal=anything displays the invalid-email alert. This particularly affects successful-submission URLs retained in history from when htmlRedirect() used the saved signal; validate that the decoded parameter is exactly invalid before revealing the banner.

Useful? React with 👍 / 👎.

Comment thread public/index.html
<div class="orn"><i></i><span class="sc">The appraisal</span><b></b><i></i></div>
<h1>Most of them leave <em>before they ever get in touch.</em></h1>
<p class="sub">We read the one page your revenue depends on the way a customer with intent reads it, and show you the exact points at which they go.</p>
<p class="signal" id="signal-invalid" role="alert" tabindex="-1" hidden>We could not save that request — the email address did not pass. Check it and try again.</p>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Provide rejection feedback without JavaScript

When JavaScript is disabled or index.js fails to load, an invalid HTML form submission still redirects through htmlRedirect() to /?signal=invalid, but this element remains hidden forever, leaving the same silent bounce this change is intended to fix. The native form and Worker explicitly support no-JavaScript submissions, so the redirected response needs a server-rendered or <noscript> rejection message rather than relying exclusively on script to remove hidden.

Useful? React with 👍 / 👎.

The worker 303-redirects a rejected signup back to /?signal=invalid
(its email regex is stricter than the browser's type=email check —
'a@b' passes client-side but not server-side), but no page code ever
read that signal: the visitor was silently bounced to the homepage
with zero feedback and their input gone.

Reveal a role=alert banner when ?signal= invalid lands, focus it for
assistive tech, then strip the query so a refresh or a copied link
does not re-show the error. Deterministic source guards in
check-site.mjs keep the banner, the handler and the worker redirect
wired together, and a worker test locks the 303 -> /?signal=invalid
contract and that rejected signups persist no row.
@nish3451
nish3451 force-pushed the fix/signup-signal-error-banner branch from c87126d to 1aa08c5 Compare August 11, 2026 12:13

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: afbbee3df8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread public/index.css
form button:hover{transform:translateY(-1.5px)}
.signal{display:block;margin:18px auto 0;max-width:500px;padding:10px 18px;font-size:14px;line-height:1.6;
color:var(--sig);background:rgba(255,253,248,.74);border:1px solid rgba(176,74,46,.35);
border-radius:12px;text-align:center}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve a visible focus indicator on the alert

When a sighted keyboard user submits an email rejected by the server, index.js moves focus to this banner, but this rule removes the only focus indicator without providing an alternative. The user therefore cannot visually determine where focus landed after the redirect; keep the outline or replace it with an equally visible :focus treatment.

Useful? React with 👍 / 👎.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e1a36091d9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/check-site.mjs
Comment on lines +292 to +296
if (!homeScript.includes("signal-invalid")) {
failures.push("index.js must reference the signal-invalid banner.");
}
if (!/signal=([^&]+)/.test(homeScript)) {
failures.push("index.js must read the ?signal= query parameter.");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Exercise the rejection handler instead of matching tokens

These checks never verify that the banner is revealed or focused, so a regression such as changing banner.hidden=false to banner.hidden=true while leaving the query parsing and element lookup intact still passes npm test; the worker test only covers the redirect, meaning invalid submissions can silently lose their feedback again with a green suite. Add a behavioral DOM test or source assertions that specifically cover the reveal and focus operations.

Useful? React with 👍 / 👎.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@nish3451
nish3451 merged commit 3efeb82 into main Aug 13, 2026
3 checks passed
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