openvibers/openvibe.network Commits

Answer the trust-signals twin and stop linking the templated people route (#695)

OP OpenVibers committed 4 days ago · 70b7d09c7d · 3 files, +16 −3

The trust-signals document answers /docs/trust-signals, but llms.txt's
markdown twin mode links /docs/trust-signals.md, which 404ed. Answer both
addresses with the same Markdown.

llms.txt also linked /api/v1/people/@handle/page. @handle is a variable,
not a page, so it is written as code in the llms.txt details instead of
a link; no checker GETs the literal address. The route and its note are
kept.

Changes

ddiff --git a/server/home/render.js b/server/home/render.js
iindex 95ba138c..1f97ec92 100644
---- a/server/home/render.js
++++ b/server/home/render.js
@@@ -480,10 +480,13 @@ const ACCOUNT_ID_LINK = {
note: 'the caller\'s own usr_… id: the account id apps and robots ask for. A person sees their own on their account page (openvibe.network/my); nobody else can read it',
};
const ACCOUNT_ID_TEXT = 'GET /api/auth/me with a person\'s token answers { user: { subject_id: "usr_…" } }. That usr_… value is the person\'s OpenVibe account ID: what apps and robots ask for when they ask for someone\'s OpenVibe account ID. A person sees their own on their account page (https://openvibe.network/my); nobody else can read it.';
++// A path with a variable is a route to call, not a page to fetch: it is written as code in llms.txt, never as a
++// Markdown link, so an agent (or a checker doing a GET) does not ask for the literal @handle address.
++const API_ROUTE_TEXT = 'API routes with a variable in the path are code, not pages to fetch: `GET /api/v1/people/@handle/page` is the signed-out profile at https://openvibe.network/@handle, including its public OpenVibe places.';
function llmsTxt() {
const { catalog } = toolsCatalog.peek();
-- return seo.llmsTxt({ name: 'OpenVibe Network', summary: llmsSummary(), markdown: true, base: 'https://openvibe.network',
++ return seo.llmsTxt({ name: 'OpenVibe Network', summary: llmsSummary(), details: API_ROUTE_TEXT, markdown: true, base: 'https://openvibe.network',
sections: [
{ title: 'Sites', links: OPEN.map((site) => ({ title: siteName(site), url: `https://${site.host}/`, note: site.what })) },
// A person's account ID: the endpoint an agent needs when it works for someone.
@@@ -498,7 +501,6 @@ function llmsTxt() {
// The JSON an agent came for is a main section, not something to skip (AGT-5 review).
{ title: 'Machine-readable', links: [
{ title: 'Open stats (JSON): every site\'s numbers', url: 'https://openvibe.network/api/v1/stats' },
-- { title: 'Public person page (JSON)', url: 'https://openvibe.network/api/v1/people/@handle/page', note: 'the signed-out profile at https://openvibe.network/@handle, including its public OpenVibe places' },
{ title: 'Trust signals (developer docs)', url: 'https://openvibe.network/docs/trust-signals', note: 'privacy-limited account and guest trust signals, API examples and fields' },
{ title: 'OpenVibe Connect MCP', url: 'https://connect.openvibe.network/mcp', note: 'includes network.person_page.read and network.my_trust.read' },
{ title: 'Tool catalog (JSON)', url: 'https://openvibe.tools/api/catalog.json' },
ddiff --git a/server/index.js b/server/index.js
iindex aaab03c2..2dd34c23 100644
---- a/server/index.js
++++ b/server/index.js
@@@ -63,7 +63,7 @@ app.get('/openapi.json', (_req, res) => {
}
res.set('Cache-Control', 'public, max-age=3600').set('Access-Control-Allow-Origin', '*').json({ ...doc, paths });
});
--app.get('/docs/trust-signals', (_req, res) => {
++app.get(['/docs/trust-signals', '/docs/trust-signals.md'], (_req, res) => {
res.type('text/markdown').set('Cache-Control', cache.htmlHeaders({ maxAge: 3600 }))
.send(fs.readFileSync(path.join(__dirname, '..', 'docs', 'trust-signals.md'), 'utf8'));
});
ddiff --git a/test/seo-routes.test.js b/test/seo-routes.test.js
iindex b39c2ebc..9369e4df 100644
---- a/test/seo-routes.test.js
++++ b/test/seo-routes.test.js
@@@ -72,6 +72,17 @@ const cache = require('openvibe-shared/cache-policy');
assert.ok(Buffer.byteLength(fullBody) <= render.LLMS_FULL_MAX_BYTES, 'llms-full.txt stays within maxBytes');
assert.strictEqual(render.LLMS_FULL_MAX_BYTES, 512 * 1024);
++ // ── the trust-signals twin, and the templated people route as code ──
++ const signals = await get('/docs/trust-signals.md');
++ assert.strictEqual(signals.status, 200, '/docs/trust-signals.md answers 200');
++ assert.match(signals.type, /^text\/markdown/, '/docs/trust-signals.md is Markdown');
++ assert.ok(signals.body.startsWith('# Trust signals'), 'the twin names the page heading');
++ const signalsPage = await get('/docs/trust-signals');
++ assert.strictEqual(signalsPage.status, 200, '/docs/trust-signals keeps answering');
++ assert.strictEqual(signalsPage.body, signals.body, 'the page and its .md twin are one document');
++ assert.ok(!llms.body.includes('](/api/v1/people/@handle/page)'), 'the templated people route is not a link');
++ assert.ok(llms.body.includes('`GET /api/v1/people/@handle/page`'), 'the templated people route is written as code');
++
// ── the front door and /stats state they may be indexed (SEO-8) ──
for (const p of ['/', '/stats']) {
const page = await get(p);