Skip to content

Bring the docs in line with the tracked origin config - #1587

Merged
feruzm merged 3 commits into
developfrom
docs/origin-tracking-drift
Aug 20, 2026
Merged

Bring the docs in line with the tracked origin config#1587
feruzm merged 3 commits into
developfrom
docs/origin-tracking-drift

Conversation

@feruzm

@feruzm feruzm commented Aug 20, 2026

Copy link
Copy Markdown
Member

Documentation and comments only, no code. Found by auditing the repo against what #1574, #1578 and #1579 actually changed.

The docs still say the origin nginx lives somewhere else

docs/cache/nginx.md had drifted into contradicting the tracked file

It carried a hand-copied server { … } block. Two lines were actively wrong:

  • add_header X-Cache-Tier $upstream_http_x_cache_tier always; — the tracked vhost has an explicit NOTE forbidding this: the upstream already sets the header and nginx proxies it through, so adding it emitted the header twice on every response.
  • always on X-Cache-Status — the real config deliberately omits it, because that value is a cache diagnostic and not something we owe an error response.

Replaced with the directives that are actually stable, plus a pointer to infra/origin/*.conf. One copy instead of two that disagree. Also noted that the $html_limited_bot map lives at http level and is not tracked, and must stay in step with htmlLimitedBots in next.config.js — if the app serves a blocking render to an agent the map does not classify, that response and a browser's share a cache entry.

Corrected eu/us/asia.ecency.com to the two live origins in nginx.md; left the same stale claim in cloudflare-worker.md alone since the worker's origin list is its own subject.

CLAUDE.md was missing a whole tracked tier and two thirds of the CI gates

  • "Workspace Structure" listed only apps/* and packages/*; infra/origin now has an entry stating the public-repo contract and that CI does not deploy it.
  • "Testing & Linting" described pnpm test/lint/typecheck as the checks. Three script audits also gate typecheck.yml and pnpm test runs none of them, so they are listed with what each enforces and why --self-test runs first.

Rationale that only existed in a commit message

infra/origin/README.md now records why location / must not answer HEAD itself, and why the always flags are the other half of that fix rather than a tidy-up: while every HEAD was a fabricated 200 those headers applied (200 is in add_header's default status list), so deleting the block alone would have dropped HSTS from real 404/429/5xx. Plus the verification trap — through Cloudflare the bug reported as already fixed.

typecheck.yml's new audit step was the only one in the file without a comment saying what it enforces.

Smaller

  • apps/web/.env.template did not say the sitekey is inlined at build time, so setting it only in the runtime environment silently falls back to the literal.
  • apps/self-hosted/hosting/nginx-multi-tenant.conf justified not routing tenant subscribes through public ecency.com partly because "a bot challenge would break the form outright". Since Require a bot check on anonymous newsletter subscribes, and offer the post prompt to anonymous readers #1579 the form carries a Turnstile widget of its own, solved in-page — a different thing from an edge interstitial the reader could not clear. Corrected in both copies; the block is byte-identical in two server blocks and nothing in CI compares them.

Verification

origin-config-audit --self-test (34 cases) and --fail both pass — worth running here because the audit scans .md as well, so a docs change can fail it.

The nginx change is comment-only. I have not applied it to the blogs host; CI deploys that file.

README and docs/cache both still filed the origin nginx as living
somewhere else. It has been in this repo since #1574, with a public-repo
contract and a CI guard, and neither was mentioned anywhere a reader
would look.

docs/cache/nginx.md carried a hand-copied server block that had drifted
into contradicting the tracked file: it showed X-Cache-Tier with always,
which the vhost explicitly forbids because the upstream already sets that
header and adding it emitted the header twice on every response, and it
showed always on X-Cache-Status, which the real config deliberately
omits. Replaced with the stable directives and a pointer to the file, so
there is one copy rather than two that disagree.

CLAUDE.md listed only apps and packages, and described pnpm test/lint/
typecheck as the checks, while three script audits gate the typecheck
workflow and pnpm test runs none of them.

The origin README now records why HEAD must not be answered in
location /, and why the always flags are the other half of that fix
rather than a tidy-up: those statuses were unreachable while every HEAD
was a fabricated 200, so the deletion alone would have dropped HSTS from
error responses.

Also: the sitekey is inlined at build time, which the env template did
not say, and the tenant nginx comment predates the Turnstile widget the
form now carries.
@coderabbitai

coderabbitai Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

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

Next review available in: 27 minutes

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f4a41620-5e11-493a-929d-df39d4e379b6

📥 Commits

Reviewing files that changed from the base of the PR and between ac429d4 and 3b545b3.

📒 Files selected for processing (8)
  • .github/workflows/typecheck.yml
  • CLAUDE.md
  • README.md
  • apps/self-hosted/hosting/nginx-multi-tenant.conf
  • apps/web/.env.template
  • docs/cache/README.md
  • docs/cache/nginx.md
  • infra/origin/README.md

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider

Great, no issues found!

Qodo reviewed your code and found no material issues that require review

Grey Divider

Tip of the day
💡 Did you know, you can copy the agent prompt from any finding and feed it to your IDE agent

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

1 similar comment
@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider

Great, no issues found!

Qodo reviewed your code and found no material issues that require review

Grey Divider

Tip of the day
💡 Did you know, you can copy the agent prompt from any finding and feed it to your IDE agent

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Aug 20, 2026

Copy link
Copy Markdown

PR Summary by Qodo

Align docs with tracked origin nginx configuration

📝 Documentation ⚙️ Configuration changes 🕐 20-40 Minutes

Grey Divider

AI Description

• Document infra/origin as the tracked origin vhost source of truth and manual deployment process.
• Remove the drifting nginx vhost snippet; keep only stable directives and link to tracked configs.
• Expand contributor docs to cover CI-gated script audits and the origin-config public-repo
 contract.
Diagram

graph TD
  Docs["Docs (README + cache)"] --> Vhosts["infra/origin vhosts"] --> Hosts("Origin hosts")
  CI["CI: typecheck.yml"] --> Audit["origin-config-audit"] --> Vhosts
  Client["Clients"] --> Worker["CF worker (infra repo)"] --> Hosts --> App["vision_web"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Generate docs from tracked vhosts (single-source publishing)
  • ➕ Eliminates drift risk entirely (docs rendered from the actual configs)
  • ➕ Makes reviewers validate behavior by reading one artifact
  • ➖ Adds tooling/CI complexity and may require sanitization for public output
  • ➖ Harder to keep docs concise/approachable for non-nginx readers
2. Move origin vhosts back to a private infra repo
  • ➕ Avoids the need for a strict public-repo contract and related audits
  • ➕ Allows embedding thresholds/addresses directly without include indirection
  • ➖ Reintroduces discoverability problems that led to this PR
  • ➖ Splits code+infra understanding across repos again
3. Automate deployment of `infra/origin` via CI/CD with secret injection
  • ➕ Reduces manual apply/reload drift risk between tracked and running config
  • ➕ Can enforce two-host consistency automatically
  • ➖ Requires secure secret/address injection and careful fail-safe design
  • ➖ Out of scope for a docs-only alignment PR and increases operational coupling

Recommendation: The PR’s approach (remove duplicated snippets and explicitly point docs to infra/origin/* as the canonical source, while documenting the public-repo constraints and CI auditing) is the best immediate choice: it minimizes drift without introducing new tooling or operational risk. If drift recurs, consider a lightweight “generate/sync docs from vhosts” step, but keep the published output intentionally conceptual/sanitized.

Files changed (8) +98 / -47

Documentation (7) +93 / -47
CLAUDE.mdDocument CI-gated audits and the 'infra/origin' tier +22/-0

Document CI-gated audits and the 'infra/origin' tier

• Adds a dedicated section listing the three script audits plus 'origin-config-audit' (self-test then fail) that gate the typecheck workflow. Updates workspace structure to include 'infra/origin', clarifying the public-repo contract and manual deployment expectations.

CLAUDE.md

README.mdCorrect infra ownership statement for origin nginx vs CF worker +3/-2

Correct infra ownership statement for origin nginx vs CF worker

• Updates the infra configuration section to state that origin nginx vhosts are tracked in this repo under 'infra/origin' and audited in CI, while the Cloudflare worker remains in the infra repo.

README.md

nginx-multi-tenant.confClarify edge bot-challenge risk vs in-form Turnstile +10/-4

Clarify edge bot-challenge risk vs in-form Turnstile

• Refines comments explaining why tenant signup must not traverse public ecency.com (Cloudflare hop), distinguishing edge interstitial challenges from the in-page Turnstile widget verified by the relay.

apps/self-hosted/hosting/nginx-multi-tenant.conf

.env.templateDocument build-time inlining of Turnstile sitekey +4/-0

Document build-time inlining of Turnstile sitekey

• Adds a warning comment that 'NEXT_PUBLIC_TURNSTILE_SITEKEY' is inlined at build time (Docker ARG / workflows) and that runtime-only configuration won’t affect the client behavior.

apps/web/.env.template

README.mdReclassify origin nginx as tracked-in-repo and manually applied +6/-1

Reclassify origin nginx as tracked-in-repo and manually applied

• Moves origin nginx from “Operated outside this repo” to a new “Tracked here, applied by hand” section, linking to 'infra/origin/README.md' and explaining the public-repo contract context.

docs/cache/README.md

nginx.mdRemove drifting vhost snippet; point to 'infra/origin/*.conf' +26/-38

Remove drifting vhost snippet; point to 'infra/origin/*.conf'

• Replaces a hand-copied 'server {}' example (which had drifted, including incorrect 'add_header' usage) with stable conceptual directives and a strong pointer to the tracked EU/US vhost files. Adds a note that the '$html_limited_bot' map is untracked at 'http' level and must stay aligned with 'htmlLimitedBots' in 'next.config.js'.

docs/cache/nginx.md

README.mdRecord HEAD-handling and 'add_header always' rationale +22/-2

Record HEAD-handling and 'add_header always' rationale

• Expands the contract documentation to explain why 'location /' must not fabricate HEAD responses, and why 'always' on security/CORS headers is integral to the fix rather than cosmetic. Adds an explicit warning to verify behavior against the origin directly (Cloudflare can mask the bug).

infra/origin/README.md

Other (1) +5 / -0
typecheck.ymlExplain rationale for origin-config audit step +5/-0

Explain rationale for origin-config audit step

• Adds an inline comment documenting why 'origin-config-audit' exists (public repo + production vhosts) and why '--self-test' runs first to prevent silent rule degradation.

.github/workflows/typecheck.yml

@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: 91daabc45c

ℹ️ 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 docs/cache/nginx.md Outdated
Comment on lines +28 to +30
⛔ **The vhosts are tracked: read `infra/origin/eu.ecency.com.conf` and
`us.ecency.com.conf` rather than a snippet here.** This section used to carry a
hand-copied `server { … }` block, which drifted and began contradicting the real config

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve the bot map consumed by the parity spec

Removing the $html_limited_bot { ... } block makes apps/web/src/specs/features/next-middleware/social-bot-metadata.spec.ts deterministically fail: lines 114–116 read this document and require that exact map before comparing it with htmlLimitedBots. Consequently every workflow running pnpm -r test, including PR-branch.yml, fails with “the $html_limited_bot map is missing”; retain a machine-readable copy or update the parity test to read another canonical source.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Confirmed and fixed in fa62b35. This was a real break and my judgement was wrong.

I read the whole ## Per-host config block as a stale hand-copy. Half of it was: the server { … } stanza had drifted into contradicting the tracked vhost, showing add_header X-Cache-Tier … always which infra/origin/eu.ecency.com.conf explicitly forbids because the upstream already sets it and adding it emitted the header twice on every response.

The map had not drifted, and is duplicated because it is enforced. social-bot-metadata.spec.ts:114-116 parses it out of this file and asserts term-for-term parity with htmlLimitedBots in next.config.js. So the block is not documentation of the config — it is a checked copy.

The part that should have stopped me: I wrote the invariant into my replacement text ("must stay in step with htmlLimitedBots") in the same edit that deleted the thing enforcing it. Documenting a rule while removing its enforcement is the exact failure the spec exists to prevent.

Restored, under a heading that says so rather than leaving the next reader to make the same call:

The bot map is CANONICAL here — do not remove it

⛔ This block is not documentation of the config, it IS a copy the test suite reads … Keep the fenced nginx block and the "~*( … )" shape — the test matches on them.

The stale server { } stanza stays removed, since that half of the finding was correct.

Verified: social-bot-metadata.spec.ts 5/5 (it was 4 passed / 1 failed, matching the repro), the whole next-middleware suite 165/165, and the full web suite 3090/3090.

Comment thread CLAUDE.md Outdated
```bash
node scripts/icon-tsx-audit.mjs --fail # icon sizing, see docs/icons.md
node scripts/icon-scss-audit.mjs # also fails if a retired SCSS rule reappears
node scripts/slim-entries-audit.mjs # feed payload invariants

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 Run the slim-entry audit in failing mode

When the slim-entry audit finds a violation, this documented command still exits successfully because scripts/slim-entries-audit.mjs only returns status 1 when --fail is present. Anyone following this new audit checklist can therefore miss the feed-payload violations that CI rejects; add --fail here to match the workflow command.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Both correct, fixed in fa62b35.

slim-entries-audit.mjs only exits 1 with --fail, so the command as I wrote it would report violations and exit 0 — the worst shape for a checklist, since it passes locally and fails in CI. And the heading said "Three" while listing four.

Now matched to typecheck.yml line for line, with the flags called out rather than left to be noticed:

node scripts/icon-scss-audit.mjs                 # also fails if a retired SCSS rule reappears
node scripts/icon-tsx-audit.mjs --fail           # icon sizing, see docs/icons.md
node scripts/slim-entries-audit.mjs --fail       # feed payload invariants
node scripts/origin-config-audit.mjs --self-test  # prove the rules still fire, THEN enforce
node scripts/origin-config-audit.mjs --fail

with "⛔ Copy the flags exactly: without --fail these REPORT and exit 0, so a violation passes locally and fails in CI."

Ordered as CI runs them, and icon-scss-audit deliberately has no flag because that is how the workflow invokes it.

@greptile-apps

greptile-apps Bot commented Aug 20, 2026

Copy link
Copy Markdown

Greptile Summary

The PR aligns repository documentation and comments with the tracked origin configuration and current CI audit commands.

  • Restores the canonical nginx bot map consumed by the web parity test while directing readers to the tracked origin vhosts for the remaining configuration.
  • Documents the origin configuration’s manual deployment model, public-repository constraints, and HEAD/header behavior.
  • Updates contributor guidance for CI audits, build-time Turnstile configuration, caching verification, and newsletter proxy rationale.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
docs/cache/nginx.md Restores the test-consumed canonical bot map and replaces the stale copied vhost with references to tracked configuration.
CLAUDE.md Documents the tracked origin tier and the audit commands currently enforced by the typecheck workflow.
infra/origin/README.md Adds operational rationale for forwarding HEAD requests and retaining security headers on error responses.
.github/workflows/typecheck.yml Adds explanatory comments to the existing origin-configuration audit step without changing workflow behavior.
README.md Corrects cache-verification guidance and identifies the repository location and deployment model of origin vhosts.

Reviews (3): Last reviewed commit: "Attribute the HEAD fix to the PR that ma..." | Re-trigger Greptile

Comment thread docs/cache/nginx.md Outdated
Comment thread CLAUDE.md Outdated
feruzm added 2 commits August 20, 2026 19:42
Removing it broke the parity test that reads it. social-bot-metadata
parses the $html_limited_bot map out of docs/cache/nginx.md and asserts
term-for-term agreement with htmlLimitedBots in next.config.js, because
drift there is invisible in dev and in production serves a
browser-primed page to a crawler from the wrong cache namespace (#1257).

I judged the whole block a stale hand-copy. Half of it was: the server
stanza had drifted into contradicting the tracked vhost. The map had
not, and is deliberately duplicated BECAUSE it is enforced. I even wrote
the invariant into the replacement text while deleting the thing that
enforces it, so the section now says plainly that the block is machine
read and names the spec that reads it.

Also: the audit list said three and listed four, and omitted --fail on
slim-entries, so following it locally would report and exit 0 while CI
failed. And the cache verification recipe claimed logged-in /discover
always bypasses, contradicting cache-policy.ts (tier list, s-maxage 300)
and the README's own note eighty lines above that only the mute-filtered
tiers go private. Replaced with a tier that genuinely bypasses.
#1575 is the issue describing the fabricated 200; #1578 is the PR that
removed it. The line read as though the issue did the work, which sends
anyone following it to a report rather than a diff. Cites both now, since
each answers a different question: the PR carries the change and the
before/after measurements, the issue carries the reproduction.

The main README already said #1578, so the two agree again.
@feruzm

feruzm commented Aug 20, 2026

Copy link
Copy Markdown
Member Author

Fixed in 3b545b3.

Confirmed against the API rather than from memory: #1575 is the issue ("Origin vhosts answer every HEAD request with a fabricated 200") and #1578 is the PR ("Stop fabricating 200 for every HEAD at the origins"). The line read as though the issue did the work, which sends anyone following it to a report rather than a diff.

Now cites both, because each answers a different question:

Removed 2026-08-20 by #1578, which closed #1575 — the PR carries the change and the before/after measurements, the issue carries the reproduction.

Swept the branch for the same mistake: the only other reference is README.md:140, which already said #1578, so the two agree again.

origin-config-audit still clean (0 findings, 34 self-test cases) — worth re-running on any change here, since the audit scans .md too.

@feruzm
feruzm merged commit 20f90b6 into develop Aug 20, 2026
10 checks passed
@feruzm
feruzm deleted the docs/origin-tracking-drift branch August 20, 2026 19:52
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