openvibers/openvibe.network Commits
Answer the trust-signals twin and stop linking the templated people route (#695)
Changes
@@@ -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' },@@@ -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'));});@@@ -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);
@@ -480,10 +480,13 @@ const ACCOUNT_ID_LINK = {
@@ -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',
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.';
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() {
function llmsTxt() {
const { catalog } = toolsCatalog.peek();
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: [
sections: [
{ title: 'Sites', links: OPEN.map((site) => ({ title: siteName(site), url: `https://${site.host}/`, note: site.what })) },
{ 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.
// A person's account ID: the endpoint an agent needs when it works for someone.
@@ -498,7 +501,6 @@ function llmsTxt() {
@@ -498,7 +501,6 @@ function llmsTxt() {
// The JSON an agent came for is a main section, not something to skip (AGT-5 review).
// The JSON an agent came for is a main section, not something to skip (AGT-5 review).
{ title: 'Machine-readable', links: [
{ title: 'Machine-readable', links: [
{ title: 'Open stats (JSON): every site\'s numbers', url: 'https://openvibe.network/api/v1/stats' },
{ 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: '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: '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' },
{ title: 'Tool catalog (JSON)', url: 'https://openvibe.tools/api/catalog.json' },
@@ -63,7 +63,7 @@ app.get('/openapi.json', (_req, res) => {
@@ -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 });
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 }))
res.type('text/markdown').set('Cache-Control', cache.htmlHeaders({ maxAge: 3600 }))
.send(fs.readFileSync(path.join(__dirname, '..', 'docs', 'trust-signals.md'), 'utf8'));
.send(fs.readFileSync(path.join(__dirname, '..', 'docs', 'trust-signals.md'), 'utf8'));
});
});
@@ -72,6 +72,17 @@ const cache = require('openvibe-shared/cache-policy');
@@ -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.ok(Buffer.byteLength(fullBody) <= render.LLMS_FULL_MAX_BYTES, 'llms-full.txt stays within maxBytes');
assert.strictEqual(render.LLMS_FULL_MAX_BYTES, 512 * 1024);
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) ──
// ── the front door and /stats state they may be indexed (SEO-8) ──
for (const p of ['/', '/stats']) {
for (const p of ['/', '/stats']) {
const page = await get(p);
const page = await get(p);