feat(404): generate a /404.md wayfinding guide, drop the not-found scaffold - #31
Merged
Merged
Conversation
…affold
The scaffolded human-visible not-found page was intrusive — a 404 page is the
site owner's design domain, and the unstyled scaffold got rewritten anyway. Its
root-only detection was also false comfort: App Router not-found.* is
per-segment, and dynamic-route misses render the nearest one, bypassing both
the root page and the middleware's wayfinding branch (the URL matches a route
pattern). The human 404 surface now belongs entirely to the user; ax only owns
machine artifacts.
- Generate public/404.md every build: the same renderWayfinding body the
middleware serves (new URL-neutral title variant), under the standard
generated-markdown frontmatter. Gated on markdownTwins like auth.md, shown at
the review gate, size-measured, generated-marker overwrite guard, removed
when stale. Rendered from serving-manifest data with this run's outputs
(planned twins, auth guide, catalog, cards) overlaid so it describes the
build it ships with.
- Rewrite agent-404.ts as detect-and-recommend only: scan every
app/**/not-found.* (segment-level included) plus pages/404.*, and ask each
unlinked page to carry one
<link rel="alternate" type="text/markdown" href="/404.md"> tag; with no 404
page at all, recommend a standard one in the user's own design plus the tag.
Delete the scaffold, the not-found-agent-data module, and the
scaffoldAgent404 config option (config schema, defaults, init wizard).
- Report: agent404 now carries per-page granularity ({source, agentAware}[])
and the written markdownGuide path.
- Manifest contract: artifacts.notFoundMd on both shapes, included in the
middleware's protectDiscovery set so a wrapped bot-gate can't cover it.
- renderWayfinding no longer lists gated routes under "Pages that do exist" —
a login-walled page is no place to send a lost agent, and the gating policy
never advertises a gated surface as open. (Surfaced by the regenerated
goldens: the markdown-twins fixture's /private was listed.)
- Fixture goldens regenerated (every fixture now snapshots its 404.md);
fixtures/*/public/404.md gitignored per the generated-markdown convention.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
arielshulman29
added a commit
that referenced
this pull request
Aug 28, 2026
Brings in the /404.md wayfinding-guide feature (PR #31). Conflicts were the 17 report goldens (both sides regenerated them); resolved by regenerating from the merged source, so the goldens and the new twins.golden/404.md files carry the renamed generated-by marker and the 404-guide content together. One stale marker assertion in generate.test.ts updated to the renamed package. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The agent-aware 404 previously altered HTML that humans also see: an opt-in scaffolded
not-found.tsxwith an "If you are an AI agent" section. Two problems:not-found.*is per-segment: anotFound()thrown insideapp/docs/[slug]/page.tsxrenders the nearest not-found file, bypassing the root one. Those dynamic-route misses are exactly the ones the wayfinding middleware structurally can't answer (the URL matches a route pattern, so existence is only knowable at request time).New division of labor: the human-visible 404 belongs entirely to the user; ax only owns machine artifacts.
What
public/404.mdevery build — the "404 wayfinding guide": discovery links + real routes, rendered by the samerenderWayfindingthe middleware serves (new URL-neutral title variant), under the standard generated-markdown frontmatter. Gated onmarkdownTwinslikeauth.md, shown at the review gate, size-measured, generated-marker overwrite/delete guard. Rendered from serving-manifest data with this run's own outputs (planned twins, auth guide, catalog, cards) overlaid, so the guide describes the build it ships with — the CLI test pins that the twin written in the same run is linked.agent-404.tsis detect-and-recommend only. Scans everyapp/**/not-found.*(segment-level included) pluspages/404.*, across both routers. Tiered recommendations: no 404 page → create a standard one in your own design system plus one<link rel="alternate" type="text/markdown" href="/404.md" />tag; pages without the tag → one message naming exactly the unlinked files. The tag is invisible to humans; an agent that fetched the HTML 404 follows it to the guide in one hop.not-found-agent-datamodule, and thescaffoldAgent404config option (schema, defaults, init wizard — now six setup items; package is unpublished, so no deprecation path needed).agent404now carries per-page granularity (pages: [{source, agentAware}]) plus the writtenmarkdownGuidepath.artifacts.notFoundMdon both shapes, and/404.mdjoins the middleware'sprotectDiscoveryset so a wrapped bot-gate can't silently un-publish it.renderWayfindinglisted gated routes under "Pages that do exist" (the markdown-twins fixture's/privatelanded in the public file). Gated paths are now filtered — a login-walled page is no place to send a lost agent, and the gating policy never advertises a gated surface as open. Applies to the middleware body too, with a test.Verification
next buildruns (pnpm reports:regen); every fixture now snapshots its404.mdintwins.golden/, andreports:verifypasses.pnpm dogfood:middleware(realnext start+ HTTP probes) passes — negotiation, wayfinding, gated-path fall-through all intact.🤖 Generated with Claude Code