Skip to content

nginx: serve the canonical-forms essay on spiritwriter.ai - #19

Merged
aaronmarkham merged 1 commit into
mainfrom
claude/spiritwriter-pr-diffs-zn0rlp
Aug 18, 2026
Merged

nginx: serve the canonical-forms essay on spiritwriter.ai#19
aaronmarkham merged 1 commit into
mainfrom
claude/spiritwriter-pr-diffs-zn0rlp

Conversation

@aaronmarkham

Copy link
Copy Markdown
Owner

/computed-not-assigned.html deployed but was unreachable — it served the landing page instead.

Cause

spiritwriter.ai's server block never tries $uri:

# Everything else gets the landing page.
location / {
    try_files /landing.html =404;
}

Every URL on that host that isn't /static/, /favicon.ico or /healthz resolves to /landing.html. The block's own comment says so — "every URL serves /landing.html" — because when it was written, spiritwriter.ai was one page.

#18 added a second page to that host and never touched the vhost serving it. The page's rendering was verified; its reachability was not. The failure mode is a 200 with the wrong content, which is why it looked like a working link that went to the home page rather than a broken one.

Fix

An explicit location for the page:

location = /computed-not-assigned.html {
    try_files $uri =404;
}

Deliberately not try_files $uri /landing.html on the catch-all. That docroot is shared with news.spiritwriter.ai, so a $uri-first rule would also expose every news page and article on the marketing domain — a much wider change than this needs, with duplicate-content consequences across two hosts.

The trade-off is that each future standalone page needs its own location. If long-form pages become a category, the better shape is a /essays/ prefix and one location /essays/ block — but that changes an already-published URL (the spiritwriter-core README, docs/canonical-forms.md, and the essay's own canonical tag all point at the current path), so it isn't worth doing for one page.

Guard

A test reads the spiritwriter.ai server block and asserts each standalone page published for that host has a location that resolves to the real file. This bug is easy to repeat precisely because the symptom is a 200, and the existing tests all passed while the page was unreachable — they check what the generator writes, not what the server will hand back.

Suite: 72 passed.

Not verified

  • The nginx config is not syntax-checked. Neither nginx nor a docker daemon is available in this environment. The new block is structurally identical to the existing location /static/ in the same file, but nginx -t has not run against it.
  • The live URL was not re-fetched. spiritwriter.ai is blocked by this session's egress proxy, so the diagnosis rests on the config, which is unambiguous. Worth loading the page once after this deploys.

Generated by Claude Code

The essay deployed but was unreachable: spiritwriter.ai's server block
serves /landing.html for every URL it doesn't name, and never tries
$uri. So /computed-not-assigned.html returned 200 with the landing page
in it — the same failure as a 404, minus the signal that anything was
wrong.

The page was added to that host without touching the vhost that serves
it. Rendering was verified; reachability was not.

Fixed with an explicit location rather than switching the catch-all to
`try_files $uri /landing.html`. The docroot is shared with
news.spiritwriter.ai, so a $uri-first rule would also expose every news
page and article on the marketing domain — a wider change than this
needs, with duplicate-content consequences.

Adds a test that reads the vhost block and asserts each standalone page
published for that host has a location resolving to the real file. The
class of bug is easy to repeat, because the symptom is a 200.

Not syntax-checked: neither nginx nor a docker daemon is available in
this environment. The new block is structurally identical to the
existing `location /static/` in the same file.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RyrQHRdQXXsfTbKvRnxKjA
@aaronmarkham
aaronmarkham merged commit bb0a622 into main Aug 18, 2026
1 check 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.

2 participants