Skip to content

docs(hutch): note homepage A/B noindex + canonical=/ is intentional defence-in-depth#928

Open
FagnerMartinsBrack wants to merge 2 commits into
mainfrom
claude/homepage-robots-noindex-comment-58et30
Open

docs(hutch): note homepage A/B noindex + canonical=/ is intentional defence-in-depth#928
FagnerMartinsBrack wants to merge 2 commits into
mainfrom
claude/homepage-robots-noindex-comment-58et30

Conversation

@FagnerMartinsBrack

Copy link
Copy Markdown
Member

What & why

Stacked on #908. Adds a single explanatory comment beside the homepage A/B robots line in home.component.ts — no behaviour change.

The A/B arms render robots: noindex, follow while keeping canonical=/. Because the server-side isbot gate already assigns bots the control / (so a crawler never follows the client redirect into an arm), that noindex + canonical=/ pairing can read as redundant to a future maintainer. The comment records that the redundancy is deliberate defence-in-depth, so nobody strips one half on the assumption the other already covers it.

// The A/B arms are noindex so only the canonical `/` competes for SEO;
// the canonical above stays on `/` for all three renders.
// Defence-in-depth: the isbot gate already keeps crawlers off the arms, so pairing noindex with canonical=`/` here is deliberately redundant — don't remove either half.
robots: variant ? "noindex, follow" : "index, follow",

Base

Targets claude/homepage-ab-redirect-g6vdrs (the #908 branch) because the robots line only exists there; the diff is a single comment line. GitHub will retarget this PR to main automatically once #908 merges.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Sfj512E2zhVqMoHpwTewdg


Generated by Claude Code

@FagnerMartinsBrack FagnerMartinsBrack force-pushed the claude/homepage-ab-redirect-g6vdrs branch from 612e329 to dfa2d2f Compare July 4, 2026 18:14
Base automatically changed from claude/homepage-ab-redirect-g6vdrs to main July 5, 2026 06:20
@FagnerMartinsBrack

Copy link
Copy Markdown
Member Author

@claude Resolve conflicts. Use your Read tool to read the local file .github/workflows/claude-PR-conflict-fixer.md for instructions. The file is in the checked-out repository.

Context

@claude

claude Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Claude finished @FagnerMartinsBrack's task in 18m 1s —— View job


✅ Conflicts resolved — branch rebased onto main

  • Read conflict-fixer instructions & PR commit history
  • Fetch origin & rebase onto origin/main
  • Resolve merge conflicts (cross-referencing PR intent)
  • Run pnpm nx run hutch:check to verify
  • Force-push with --force-with-lease

Root cause of the conflicts

PR #908 — the branch this was stacked on — already squash-merged into main (393beba4). So all four preparatory commits (feat / detectInstallBrowser refactor / server-side isbot gate / queue-flow E2E decouple) are already on main; every ADDED file (homepage-split.*, landing/*) matched by blob SHA. main then went a step further and refactored home.component.ts's params into a HomePageParams discriminated union — a change that must not be reverted.

A plain git rebase replays all five commits, so the four already-merged ones collide (add/add + content conflicts across 9 files), and resolving them branch-side would have clobbered main's union refactor.

Resolution

The only genuinely-new commit on this branch is the docs comment (0701ed7d). So instead of fighting nine spurious conflicts, I reset the branch to origin/main and cherry-picked just that commit. It applied cleanly on top of the union refactor because the anchor lines (the existing 2-line SEO comment + the robots: line) are unchanged on main.

Net diff vs main is now exactly the intended one line — nothing from main is reverted:

export function HomePage(params: HomePageParams): PageBody {   // ← main's union refactor, preserved
  
  // The A/B arms are noindex so only the canonical `/` competes for SEO;
  // the canonical above stays on `/` for all three renders.
+ // Defence-in-depth: the isbot gate already keeps crawlers off the arms, so pairing noindex with canonical=`/` here is deliberately redundant — don't remove either half.
  robots: variant ? "noindex, follow" : "index, follow",

Verification

  • pnpm nx run hutch:checkgreen (all 29 dependent tasks; the initial failures were purely missing local env vars, fixed by sourcing .envrc).
  • Coverage thresholds met: statements 99.53%, branches 97.21%, functions 100%, lines 99.53%.
  • git merge-tree against the current origin/main (which advanced to 8bde9e69 mid-run) confirms the branch now merges cleanly with zero conflicts — history is a clean linear main + 1 commit.

(Posting the summary here in my existing comment rather than a separate gh pr comment, per the automation's single-comment rule.)
· claude/homepage-robots-noindex-comment-58et30

@FagnerMartinsBrack FagnerMartinsBrack force-pushed the claude/homepage-robots-noindex-comment-58et30 branch from 0701ed7 to 623ae28 Compare July 5, 2026 06:55
@FagnerMartinsBrack

Copy link
Copy Markdown
Member Author

@claude Review this PR. Use your Read tool to read the local file .github/workflows/claude-PR-code-reviewer.md for instructions. The file is in the checked-out repository.

Context

@claude

claude Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Claude finished @FagnerMartinsBrack's task in 5m 40s —— View job


Review — docs(hutch): homepage A/B noindex + canonical=/ (comment-only, +1/-0)

I traced the full A/B path to check the claim in the new comment against the actual code:

  • Server gate (server.ts:679): const abSplit = !isbot(req.get("user-agent")) → a bot hitting / gets the control (index, follow, canonical /) and no split-redirect script. ✔ accurate.
  • Arms (landing.routes.ts:49-54): /landing-a and /landing-b are plain, un-gated GET routes. renderLanding has no isbot check.
  • robots.txt (server.ts:472-499): Allow: /, disallows only /queue, /export, /oauth, /forgot-password — the arms are not disallowed.
  • sitemap.xml (server.ts:519-543): the arms are not listed.

The behaviour is correct and unchanged; the only reviewable dimension is whether the comment's reasoning is accurate (it's the entire payload of the PR).

High Priority Issues (Must Fix)

None found

Medium Priority Issues

1. "deliberately redundant" mischaracterises the mechanism — and could invite the exact removal it warns against

// Defence-in-depth: the isbot gate already keeps crawlers off the arms, so pairing noindex with canonical=`/` here is deliberately redundant — don't remove either half.

The isbot gate and the arm noindex cover different paths, so they're complementary, not redundant:

  • The isbot gate on / only stops a crawler from discovering an arm via the client redirect.
  • A crawler that requests /landing-a directly (leaked Referer, someone links it, an enumerating scraper) is not bot-gated — renderLanding has no isbot check — and is not disallowed in robots.txt, and the arms aren't in the sitemap to signal otherwise. For that path the noindex is the sole thing keeping the page out of the index, not a redundant backup.

This matters because the comment's whole job is to stop a future maintainer removing a half. Telling them the pairing is "deliberately redundant" because "the isbot gate already keeps crawlers off the arms" invites the inference "redundant ⇒ safe to drop" — the opposite of the intended message. The accurate framing ("the isbot gate covers the redirect-discovery path; the noindex is the only guard for direct hits to the arm URLs") is a stronger argument for keeping both halves. Suggested reword:

// The A/B arms are noindex so only the canonical `/` competes for SEO; the canonical
// above stays on `/` for all three renders. This is defence-in-depth, not redundancy:
// the isbot gate on `/` only stops crawlers discovering the arms via the client redirect —
// a direct hit to a `/landing-*` URL is not bot-gated and not disallowed in robots.txt, so
// this noindex is the only guard keeping such a hit out of the index. Don't remove either half.

Fix this →

Low Priority Suggestions

1. Tighten the now three-line block and wrap to ~100 cols

The new line is a single ~180-char line appended below a two-line block that already says "only the canonical / competes for SEO" and "the canonical … stays on /". The surrounding comments in this file wrap at ~100 columns; the reword above folds all three lines into one wrapped block and drops the repetition. Pure formatting — bundle it into the MEDIUM reword rather than as a separate change.

2. Comment policy — the comment itself is justified

Per the code-comments skill, a why-comment is allowed only when the reason isn't recoverable from history. Here it holds up: #908's squash commit is a bare one-liner (add homepage A/B split redirect infrastructure) and server.ts:677-678 carries only half the rationale, so the defence-in-depth pairing isn't discoverable elsewhere, and the human opened this PR specifically to add it (approval gate satisfied). No action needed — noting it so the comment isn't later flagged as an unapproved addition.

This PR has issues that should be addressed before merging.
· claude/homepage-robots-noindex-comment-58et30

@FagnerMartinsBrack

Copy link
Copy Markdown
Member Author

High Priority Issues (Must Fix)

None found

Medium Priority Issues

1. "deliberately redundant" mischaracterises the mechanism — and could invite the exact removal it warns against

The new comment says the noindex + canonical=/ pairing is "deliberately redundant" because "the isbot gate already keeps crawlers off the arms." Tracing the code, the two mechanisms cover different paths, so they are complementary, not redundant:

  • The isbot gate (server.ts:679, abSplit = !isbot(ua)) only stops a crawler from discovering an arm via the client redirect from /.
  • A crawler that requests /landing-a directly is not bot-gated — renderLanding (landing.routes.ts:30-47) has no isbot check — and the arms are not disallowed in robots.txt (server.ts:472-499) nor listed in the sitemap (server.ts:519-543). For that path the arm noindex is the sole protection, not a redundant backup.

Because the comment exists to stop a maintainer removing a half, calling the pairing "redundant" invites the inference "redundant ⇒ safe to drop" — the opposite of intent. Rewording to "complementary" (isbot gate = redirect-discovery path; noindex = direct hits to arm URLs) is a stronger, accurate justification.

Low Priority Suggestions

1. Tighten the three-line block and wrap to ~100 columns

The added ~180-char line sits below a two-line block that already repeats the canonical-stays-on-/ point; fold the three lines into one wrapped block matching the file's ~100-col comment style.

2. Comment policy — the comment itself is justified

Per the code-comments skill, the why-comment is allowed: #908's squash commit is a bare one-liner and server.ts:677-678 carries only half the rationale, so the pairing rationale isn't recoverable from history, and the human opened this PR specifically to add it.

@FagnerMartinsBrack

Copy link
Copy Markdown
Member Author

@claude Fix the review issues. Use your Read tool to read the local file .github/workflows/claude-PR-code-review-auto-apply.md for instructions. The file is in the checked-out repository.

Context

Review to Address

See the review comment above this one for the issues to fix.

@claude

claude Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Claude finished @FagnerMartinsBrack's task in 15m 47s —— View job


✅ Review issues fixed — reworded the homepage A/B noindex comment

  • Read instructions & the review's MEDIUM issue
  • Verify the review's code claims (isbot gate, landing routes, robots.txt, sitemap)
  • Read the code-comments skill (editing a comment)
  • Reword the comment (MEDIUM fix — absorbs the LOW wrapping/folding suggestion)
  • Run pnpm nx run hutch:checkgreen
  • Commit & push (a68af815)

What was fixed

MEDIUM — "deliberately redundant" mischaracterised the mechanism. I traced the full A/B path and confirmed every claim in the review against source:

Claim Source Verdict
Bot on / gets the control, no split script server.ts:679 !isbot(req.get("user-agent"))
/landing-* is not bot-gated renderLanding (landing.routes.ts:30-54) — only a req.userId auth bounce, no isbot check
Arms not disallowed in robots.txt server.ts:472-499 disallows only /queue, /export, /oauth, /forgot-password
Arms not in the sitemap server.ts:519-543

So the isbot gate (redirect-discovery path) and the arm noindex (direct-hit path) are complementary, not redundant — calling them "redundant" invited the exact "redundant ⇒ safe to drop" inference the comment exists to prevent. Reworded to state that, and folded the old 3-line block (which repeated "canonical stays on /") into one wrapped ~90-col block, absorbing LOW #1. LOW #2 (comment is justified) needed no action.

-			// The A/B arms are noindex so only the canonical `/` competes for SEO;
-			// the canonical above stays on `/` for all three renders.
-			// Defence-in-depth: the isbot gate already keeps crawlers off the arms, so pairing noindex with canonical=`/` here is deliberately redundant — don't remove either half.
+			// The A/B arms render `noindex` with canonical=`/`, so only the canonical `/` competes for
+			// SEO across all three renders. This is defence-in-depth, not redundancy: the isbot gate on
+			// `/` only keeps crawlers off the arms they'd reach via the client redirect. A direct hit to
+			// a `/landing-*` URL is not bot-gated and not disallowed in robots.txt, so on that path the
+			// arm's own noindex + canonical=`/` are the only guard. Don't remove either half.

Verification

  • pnpm nx run hutch:checkgreen (29 tasks): 239 unit suites / 2779 tests, 11 integration, 2 E2E; coverage statements 99.53%, branches 97.21%, functions 100%, lines 99.53%.
  • Pre-commit hook (pnpm check, 36 projects / 47 tasks) also passed.

Commit note

Committed as docs(hutch):, not the workflow's generic fix: placeholder — this is a comment-only change, so per the repo's git-commit skill (Conventional Commits, the override-level source of truth) the accurate type is docs, matching the sibling commit docs(hutch): record homepage A/B noindex… that introduced this comment. No automation parses the message (the auto-fix flow tracks via auto-fix-attempt-N labels).

(Summary posted here in my existing comment rather than a separate gh pr comment, per the automation's single-comment rule.)
· claude/homepage-robots-noindex-comment-58et30

@FagnerMartinsBrack

Copy link
Copy Markdown
Member Author

@claude Review this PR. Use your Read tool to read the local file .github/workflows/claude-PR-code-reviewer.md for instructions. The file is in the checked-out repository.

Context

@claude

claude Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Claude finished @FagnerMartinsBrack's task in 3m 32s —— View job


Review — docs(hutch): homepage A/B noindex complements the isbot gate (a68af815, comment-only +5/-2)

  • Read reviewer instructions & the diff
  • Read the changed file (home.component.ts)
  • Verify the reworded comment's claims against source (isbot gate, landing routes, robots.txt, sitemap)
  • Check comment-policy compliance (code-comments skill)
  • Post review

This commit rewords the comment the previous review flagged. That prior MEDIUM ("deliberately redundant" mischaracterised the mechanism and could invite the removal it warns against) is the only substantive dimension, so I re-traced the whole A/B path and checked the new text line-by-line against source.

Every claim in the reworded comment is accurate:

Claim Source Verdict
Arms render noindex with canonical=/ home.component.ts:67 (canonical hardcoded /, not variant-conditional) + :74 (variant → "noindex, follow")
Only canonical / competes for SEO across all three renders control is index, both arms noindex, all three canonical /
isbot gate on / only keeps crawlers off arms reached via the client redirect server.ts:679 abSplit = !isbot(ua) gates only the split script (home.component.ts:260-264); gate lives on the / handler alone
Direct hit to /landing-* is not bot-gated renderLanding (landing.routes.ts:30-47) has only a req.userId auth bounce — no isbot check
Arms not disallowed in robots.txt server.ts:477-481 disallows only /queue, /export, /oauth, /forgot-password
(supporting) arms not in sitemap server.ts:522-532 lists /, /install, /login, /signup, /privacy, /terms, /llms*.txt, /auth.md — arms absent

Prior MEDIUM resolved. The new wording explicitly says "defence-in-depth, not redundancy" and correctly frames the two mechanisms as covering different paths — the isbot gate for the redirect-discovery path, the arm noindex for direct hits — which is a stronger, accurate argument for keeping both halves. The old prior-review LOW (fold the repetitive 3-line block, wrap to ~100 cols) is also absorbed: the block is now one wrapped ~90-col unit with the duplicate "canonical stays on /" line gone.

High Priority Issues (Must Fix)

None found

Medium Priority Issues

None found

Low Priority Suggestions

1. (Optional) The comment closes the "don't remove either half" loop but not the "don't replace with Disallow" one. The other move a future maintainer might reach for is adding /landing-* to robots.txt Disallow (server.ts:477-481) as the "proper" way to hide the arms. That would be wrong for exactly the reason the comment implies but doesn't state: a Disallowed URL can't be crawled, so the crawler never reads the noindex/canonical meta — the URL can still be indexed link-only, worse than the current allow-crawl-but-noindex design. If you want the comment to be fully future-proof you could add a half-sentence to that effect, but it's genuinely optional — the comment is already correct and complete as written, and the prior round worked to tighten it, so adding prose cuts the other way.

2. Comment policy — the comment itself remains justified. Per the code-comments skill, a why-comment is allowed only when the rationale isn't recoverable from history. It holds: #908's squash commit is a bare one-liner, and server.ts:677-678 carries only half the rationale (the redirect-discovery path), so the direct-hit half of the defence-in-depth pairing isn't discoverable elsewhere — and the human opened this PR specifically to record it. No action; noting it so the comment isn't later flagged as an unapproved addition. The docs(hutch): commit type is also correct for a comment-only change per the git-commit skill.

cc @FagnerMartinsBrack - No high or medium priority issues found. This PR is ready for human review.
· claude/homepage-robots-noindex-comment-58et30

@FagnerMartinsBrack

Copy link
Copy Markdown
Member Author

High Priority Issues (Must Fix)

None found

Medium Priority Issues

None found

Low Priority Suggestions

1. (Optional) Comment closes the "don't remove either half" loop but not the "don't replace with Disallow" one

The reworded comment is accurate and its prior MEDIUM ("deliberately redundant") is resolved. The one remaining forward-looking gap: the other move a maintainer might reach for is adding /landing-* to robots.txt Disallow (server.ts:477-481) as the "proper" way to hide the arms. That would be wrong for the reason the comment implies but doesn't state — a Disallowed URL isn't crawled, so the crawler never reads the noindex/canonical meta and the URL can still be indexed link-only, which is worse than the current allow-crawl-but-noindex design. A half-sentence would fully future-proof the comment, but it's genuinely optional: the text is already correct and complete, and the prior round worked to tighten it.

2. Comment policy — the comment itself remains justified

Per the code-comments skill, the why-comment is allowed: #908's squash commit is a bare one-liner and server.ts:677-678 carries only half the rationale (the redirect-discovery path), so the direct-hit half isn't recoverable from history, and the human opened this PR specifically to record it. docs(hutch): is the correct commit type for a comment-only change. No action needed.

claude and others added 2 commits July 9, 2026 18:54
… defence-in-depth

The server-side isbot gate already keeps crawlers on the control `/` and off
the A/B arms, so the arms' `noindex` paired with `canonical=/` reads as
redundant. Note that the redundancy is deliberate belt-and-suspenders so a
future reader does not strip one half.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sfj512E2zhVqMoHpwTewdg
… not redundant

The prior comment called the arm noindex + canonical=/ pairing "deliberately
redundant" with the server-side isbot gate. They cover different paths: the
isbot gate only keeps crawlers off the arms reached via the client redirect
from `/`, while a direct hit to a `/landing-*` URL is not bot-gated and not
disallowed in robots.txt, so there the arm noindex is the sole guard. Call
them complementary so a future reader does not drop the noindex assuming the
isbot gate already covers it.

Co-authored-by: Fayner Brack <FagnerMartinsBrack@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@FagnerMartinsBrack FagnerMartinsBrack force-pushed the claude/homepage-robots-noindex-comment-58et30 branch from a68af81 to a839934 Compare July 9, 2026 08:54
@FagnerMartinsBrack

Copy link
Copy Markdown
Member Author

@claude Review this PR. Use your Read tool to read the local file .github/workflows/claude-PR-code-reviewer.md for instructions. The file is in the checked-out repository.

Context

@claude

claude Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Claude finished @FagnerMartinsBrack's task in 5m 6s —— View job


Review — docs(hutch): homepage A/B noindex complements the isbot gate (a8399344, comment-only +5/-2)

  • Read reviewer instructions & the diff (git diff origin/main...HEAD)
  • Read the changed file (home.component.ts) — canonical / robots / split logic
  • Verify the reworded comment's claims against source (isbot gate, landing routes, robots.txt, sitemap, naive-bot)
  • Check comment-policy compliance (code-comments skill)
  • Post review

This is the first review since the branch was rebased onto main (the conflict-fixer reset to origin/main and preserved main's HomePageParams union refactor), so I re-checked rebase integrity as well as re-tracing every claim in the reworded comment against source.

Rebase is clean — net diff vs origin/main is exactly the intended comment, nothing from main reverted:

  • git diff origin/main...HEAD touches only home.component.ts (+5/-2) — the 5-line SEO comment above robots:.
  • main's discriminated-union refactor is intact: HomePageParams (home.component.ts:42-50), HomePage(params: HomePageParams) at :52. Not clobbered. ✔
  • Clean 2-commit history on top of origin/main (11c01b80 add → a8399344 reword), both correctly typed docs(hutch): for a comment-only change.

Every claim in the comment is accurate (re-verified line-by-line):

Claim Source Verdict
Arms render noindex with canonical=/ canonical hardcoded https://readplace.com at home.component.ts:74 (not variant-conditional) + :81 variant ? "noindex, follow" : "index, follow"
Only canonical / competes for SEO across all three renders control index, both arms noindex, all three share the hardcoded canonical /
isbot gate on / only keeps crawlers off arms reached via the client redirect server.ts:714 abSplit = !isbot(ua) toggles only the split script (home.component.ts:267-271); gate lives on the / handler alone
Direct hit to /landing-* is not bot-gated renderLanding (landing.routes.ts:30-47) has only a req.userId auth bounce — no isbot check
Arms not disallowed in robots.txt server.ts:501-505 disallows only /queue, /export, /oauth, /forgot-password; Allow: /
(supporting) arms not in sitemap server.ts:546-558 lists /, /install, /import, /login, /signup, /privacy, /terms, /support, /llms*.txt, /auth.md — arms absent

I also checked the naive-bot middleware as a possible hidden gate: it 403s only narrow scripted-client UAs (curl, python-requests, Go-http-client…) and deliberately lets unknown/search crawlers through (naive-bot.ts:14-15). So it doesn't serve noindex and doesn't contradict "not bot-gated" — for a search crawler's direct hit, the arm's own noindex really is the operative guard.

The prior MEDIUM ("deliberately redundant" mischaracterised the mechanism) stays resolved: the text now says "defence-in-depth, not redundancy" and correctly frames the isbot gate (redirect-discovery path) and the arm noindex (direct-hit path) as covering different paths — the stronger, accurate argument for keeping both halves.

High Priority Issues (Must Fix)

None found

Medium Priority Issues

None found

Low Priority Suggestions

1. (Optional, already raised twice) The comment closes "don't remove either half" but leaves "don't replace with Disallow" implied. A maintainer might still "fix" arm exposure by adding /landing-* to robots.txt Disallow (server.ts:501-505) — which is wrong: a Disallowed URL is never crawled, so the crawler never reads the noindex/canonical meta and the URL can still be indexed link-only, worse than the current allow-crawl-but-noindex design. The comment was deliberately tightened over two rounds and the human has left this optional line untaken both times, so I'm not re-pressing it — flagging only that it's a conscious open choice, not an oversight.

2. (Optional, wording) "noindex + canonical=/ are the only guard" slightly over-credits the canonical. On the direct-hit path the operative guard is noindex; canonical / is a consolidation hint (advisory, and technically a mixed signal on a noindex page), not a second enforcement. Immaterial — behaviour is unchanged and intent is clear — no action.

3. Comment policy — the comment remains justified. Per the code-comments skill, a why-comment is allowed only when the rationale isn't recoverable from history: #908's squash commit is a bare one-liner and server.ts:712-713 documents only the redirect-discovery half, so the direct-hit half of the pairing isn't discoverable elsewhere, and the human opened this PR specifically to record it. No action.

cc @FagnerMartinsBrack - No high or medium priority issues found. This PR is ready for human review.
· claude/homepage-robots-noindex-comment-58et30

@FagnerMartinsBrack

Copy link
Copy Markdown
Member Author

Review — docs(hutch): homepage A/B noindex complements the isbot gate (a8399344, comment-only +5/-2)

This is the first review since the branch was rebased onto main (the conflict-fixer reset to origin/main and preserved main's HomePageParams union refactor), so I re-checked rebase integrity as well as re-tracing every claim in the reworded comment against source.

Rebase is clean — net diff vs origin/main is exactly the intended comment, nothing from main reverted:

  • git diff origin/main...HEAD touches only home.component.ts (+5/-2) — the 5-line SEO comment above robots:.
  • main's discriminated-union refactor is intact: HomePageParams (home.component.ts:42-50), HomePage(params: HomePageParams) at :52. Not clobbered. ✔
  • Clean 2-commit history on top of origin/main (11c01b80 add → a8399344 reword), both correctly typed docs(hutch): for a comment-only change.

Every claim in the comment is accurate (re-verified line-by-line):

Claim Source Verdict
Arms render noindex with canonical=/ canonical hardcoded https://readplace.com at home.component.ts:74 (not variant-conditional) + :81 variant ? "noindex, follow" : "index, follow"
Only canonical / competes for SEO across all three renders control index, both arms noindex, all three share the hardcoded canonical /
isbot gate on / only keeps crawlers off arms reached via the client redirect server.ts:714 abSplit = !isbot(ua) toggles only the split script (home.component.ts:267-271); gate lives on the / handler alone
Direct hit to /landing-* is not bot-gated renderLanding (landing.routes.ts:30-47) has only a req.userId auth bounce — no isbot check
Arms not disallowed in robots.txt server.ts:501-505 disallows only /queue, /export, /oauth, /forgot-password; Allow: /
(supporting) arms not in sitemap server.ts:546-558 lists /, /install, /import, /login, /signup, /privacy, /terms, /support, /llms*.txt, /auth.md — arms absent

I also checked the naive-bot middleware as a possible hidden gate: it 403s only narrow scripted-client UAs (curl, python-requests, Go-http-client…) and deliberately lets unknown/search crawlers through (naive-bot.ts:14-15). So it doesn't serve noindex and doesn't contradict "not bot-gated" — for a search crawler's direct hit, the arm's own noindex really is the operative guard.

The prior MEDIUM ("deliberately redundant" mischaracterised the mechanism) stays resolved: the text now says "defence-in-depth, not redundancy" and correctly frames the isbot gate (redirect-discovery path) and the arm noindex (direct-hit path) as covering different paths — the stronger, accurate argument for keeping both halves.

High Priority Issues (Must Fix)

None found

Medium Priority Issues

None found

Low Priority Suggestions

1. (Optional, already raised twice) The comment closes "don't remove either half" but leaves "don't replace with Disallow" implied. A maintainer might still "fix" arm exposure by adding /landing-* to robots.txt Disallow (server.ts:501-505) — which is wrong: a Disallowed URL is never crawled, so the crawler never reads the noindex/canonical meta and the URL can still be indexed link-only, worse than the current allow-crawl-but-noindex design. The comment was deliberately tightened over two rounds and the human has left this optional line untaken both times, so I'm not re-pressing it — flagging only that it's a conscious open choice, not an oversight.

2. (Optional, wording) "noindex + canonical=/ are the only guard" slightly over-credits the canonical. On the direct-hit path the operative guard is noindex; canonical / is a consolidation hint (advisory, and technically a mixed signal on a noindex page), not a second enforcement. Immaterial — behaviour is unchanged and intent is clear — no action.

3. Comment policy — the comment remains justified. Per the code-comments skill, a why-comment is allowed only when the rationale isn't recoverable from history: #908's squash commit is a bare one-liner and server.ts:712-713 documents only the redirect-discovery half, so the direct-hit half of the pairing isn't discoverable elsewhere, and the human opened this PR specifically to record it. No action.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants