Skip to content

feat(landing): agent-surface contract: home Markdown twin, Accept negotiation, api-catalog, security.txt (T-5785) - #669

Merged
BSalaeddin merged 2 commits into
devfrom
seo/agent-surface-twins-5785
Oct 26, 2026
Merged

BSalaeddin merged 2 commits into
devfrom
seo/agent-surface-twins-5785

Conversation

@BSalaeddin

@BSalaeddin BSalaeddin commented Oct 26, 2026 •

Copy link
Copy Markdown
Collaborator

GetItDone T-5785 (fleet agent-surface contract), applied to useupup.com. Live probe 2026-10-26 with ci-tooling's scripts/agent-surface/check.py --origin https://useupup.com: 4/9. Failing: index-md, accept-markdown, alternate-link, security-txt, api-catalog. This PR makes the landing app pass all nine.

What

Surface Live before After (local prod build)
/index.md (home Markdown twin) 404 200 text/markdown, Vary: Accept, Cache-Control: private, no-store, Link: <https://useupup.com/>; rel="canonical"
/ with Accept: text/markdown HTML the twin (beforeFiles rewrite), only when no text/html comes before text/markdown; browsers, */* and no Accept keep HTML
Markdown alternate on the HTML home page none <link rel="alternate" type="text/markdown" href="https://useupup.com/index.md"> in the head and Link: </index.md>; rel="alternate"; type="text/markdown" header (missing: the Markdown Accept, so the Markdown answer carries only its canonical)
/.well-known/api-catalog 404 RFC 9727 linkset, application/linkset+json with the RFC 9727 profile, Link: rel="api-catalog"
/.well-known/security.txt 404 RFC 9116: same Contact as devino.ca, Expires 2027-04-26, Preferred-Languages, Canonical

How

  • Twin body (src/lib/home-markdown.ts) is built from the modules the home page renders: the page title/description (moved verbatim into src/lib/home-page.ts, page.tsx now reads it), the framework registry behind the hero strip and install box, the storage-provider and file-type lists of the features section (planned providers are listed as "On the roadmap", exactly as the page's planned strip), the home FAQ (lib/faqs.ts), the agent-setup pill sentence, and the site's existing links (docs, llms.txt, llms-full.txt, GitHub, Discord). No new claims.
  • Negotiation follows the proven Postify #770 / devino.ca release: 2026-08-06 QA sweep - P0 notify-modal fix, SEO/indexability, docs search, playground Geist, test cull #347 pattern: rewrites() now returns { beforeFiles, afterFiles, fallback }; the existing llms/docs-twin/PostHog/Sentry rules moved verbatim into afterFiles (the telemetry and Sentry tests read afterFiles through Next's loadCustomRoutes and still pass). /index.md is force-dynamic so Next's prerender Vary list cannot replace Vary: Accept.
  • Link header rule is added to both header sets (production HSTS set and the non-production noindex set); it is the only rule that sets Link on /.
  • /.well-known/* paths are excluded from Next's trailingSlash redirect (verified in next/dist/lib/load-custom-routes.js), so /.well-known/api-catalog is a direct 200, no 308. tsconfig.json includes src/app/.well-known/**/*.ts because ** skips dot-dirs.
  • security.txt has no Policy: line on purpose: the repo's SECURITY.md names hello@devino.com (not a devino.ca mailbox), which would contradict the Contact. Left untouched here.
  • src/proxy.ts (visitor cookie, /_t/* telemetry strip) is untouched. Unknown root .md paths stay 404; /docs/<slug>.md twins, /llms.txt and /agent-setup/prompt.md are unchanged.

api-catalog decision

upup is an SDK, not a hosted API. Its one HTTP API is the one createUpupHandler() from @useupup/server serves, and it runs on the developer's own server at whatever prefix they mount it. The catalog therefore lists that API by its wire-level reference, /docs/api-reference/server-http/ (item), with service-doc links to the HTML page, its Markdown twin /docs/api-reference/server-http.md and /llms-full.txt. No service-desc (there is no OpenAPI description). The useupup.com/api/* routes (demo backend, docs search, support form) are deliberately not listed: robots.txt keeps crawlers off /api/ and none is offered as a public API. A test pins every catalog URL to a docs page that exists.

Tests

  • New src/__tests__/agent-surface.test.ts (23 tests): the / rewrite and Link header replayed through Next's own path and has/missing matchers for Markdown, browser, */*, missing and text/html, text/markdown;q=0.1 Accept values; other pages and .md paths untouched; page metadata alternate; /index.md headers and body; the twin lists every framework, provider (planned ones only on the roadmap line), file type and FAQ, and links only to sitemap pages or the machine-readable files; api-catalog content type, profile, self-link and that every URL is a served docs page; security.txt fields, and Expires between 30 and 366 days away (deliberately date-bound: renew SECURITY_TXT_EXPIRES in src/lib/security-txt.ts when it fails).
  • Landing suite: 59 files, 836 passed. typecheck, lint (eslint, max-warnings 0), knip, prettier and the pre-commit core/react/server suites all green.

Local check.py result (next build + next start, production base URL)

$ python -I ci-tooling/scripts/agent-surface/check.py --origin http://127.0.0.1:3917
PASS  llms-txt         /llms.txt 200 text/plain, 19776 bytes
PASS  index-md         /index.md 200 text/markdown
PASS  accept-markdown  / with Accept: text/markdown is 200 text/markdown with Vary: Accept
PASS  browser-html     / with a browser Accept is 200 text/html
PASS  alternate-link   Link header advertises the Markdown alternate
PASS  security-txt     security.txt 200, Contact present, Expires 2027-04-26T00:00:00.000Z
PASS  api-catalog      api-catalog 200 application/linkset+json, 2 linkset entries
PASS  robots-ai        robots.txt lets all 10 AI crawlers read / and names a sitemap
PASS  unknown-md-404   an unknown .md path answers 404

9/9 (live prod today: 4/9). Also checked by hand on the same server: /docs/api-reference/server-http.md 200 text/markdown, /docs/llms.txt 200, /react/ with Accept: text/markdown still HTML, HSTS still on /.

After promotion

This reaches useupup.com with the next dev→master promotion. Prod proof then:

python -I ci-tooling/scripts/agent-surface/check.py --origin https://useupup.com

Expected 9/9. Cloudflare reports cf-cache-status: DYNAMIC for / today, so the edge does not cache the home HTML and the Markdown answer is never stored (it is private, no-store regardless).

Security contact fix (second commit): SECURITY.md and CODE_OF_CONDUCT.md sent reports to hello@devino.com. devino.com is not a Devino domain: its NS is Bluehost and its MX is a separate Outlook tenant, while every fleet domain is on Cloudflare. So vulnerability reports went to a third party. Both now use aladdin@devino.ca, the same contact as the new security.txt and devino.ca's.

@codesandbox

codesandbox Bot commented Oct 26, 2026

Copy link
Copy Markdown

Review or Edit in CodeSandbox

Open the branch in Web Editor • VS Code • Insiders

Open Preview

@BSalaeddin
BSalaeddin merged commit 71d0e2e into dev Oct 26, 2026
18 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