doc-platform
@ingadhoc/docs-platform
Платформа документации Adhoc: один поисковый движок, одно ядро MCP, один шлюз доступа и один защитный механизм от утечек, которые потребляются пинами из репозиториев контента (oba-docs, odumbo-docs, adhoc-docs).
До этого четыре части жили в форках в трёх репозиториях: один и тот же файл с тремя диалектами, и каждый фикс распространялся вручную — или не распространялся. Измерение находится в docs/unificacion/: lib/mcp/indice.mjs имел 41 различие между тремя копиями, и 17 из них были фиксами, которые были в одном репозитории, а в двух других — нет. Самый дорогой случай: защитный механизм от утечек был байт-идентичным в двух репозиториях и отсутствовал в третьем.
ADR 0006 из
knowledge-management— один репозиторий на корпус контента, а платформа как отдельный пакет: контент и движок имеют разные жизненные циклы и разных владельцев.ADR 0007 из
knowledge-management— шлюз и защитный механизм от утечек принадлежат платформе, а не каждому сайту: защита, которую каждый репозиторий реализует заново, — это защита, которой у какого-то репозитория нет.Этап A спецификации
arquitectura-plataforma-docs: этот пакет с двумя версионированными контрактами и drift-check, который делает видимым отставание пина.
Как потребляется
npm i --ignore-scripts github:ingadhoc/doc-platform#v0.1.0Точный пин, всегда по тегу. Никаких ^, никаких main, никаких веток: пин — это то, что предотвращает поломку трёх сайтов одновременно из-за фикса платформы, и это то, что позволяет откат одной строкой. Диапазон намеренно вызывает сбой docs-drift-check — пин, который не пинует, не является пином.
--ignore-scripts рекомендуется. У этого пакета нет ни одного install-скрипта, и не будет; флаг предназначен для всего дерева, потому что это выполняется в buildCommand публичных сайтов. По той же причине у пакета одна единственная зависимость (minisearch, которая нужна поисковому движку) и ноль devDependencies: минимальная поверхность в сборке.
Что у потребителя уже есть и этот пакет не объявляет: mcp-handler и zod, которые импортирует lib/mcp/mcp-handler.mjs. Это зависимости репозитория, намеренно: репозиторий решает, с какой версией MCP-фреймворка разворачиваться, и пакет не навязывает свою. Все три репозитория имеют их сегодня.
После npm i у репозитория-потребителя остаются три строки клея:
// api/mcp.mjs
import { crearMcp } from '@ingadhoc/docs-platform/mcp-handler';
import { crearFeedback } from '@ingadhoc/docs-platform/feedback';
import * as indice from '@ingadhoc/docs-platform/indice';
import { config } from '../docs.mcp.config.mjs';
const { handler } = crearMcp({
config,
indice,
crearIssue: crearFeedback(config.feedback),
});
export default handler; // sin default export Vercel no encuentra el handler// middleware.js — en la RAÍZ del repo (Vercel lo exige ahí)
import { next } from '@vercel/functions';
// Por RUTA RELATIVA, no por especificador de paquete: el bundler del edge
// rechaza `@ingadhoc/docs-platform/gate` cuando el repo consumidor no es
// `"type": "module"` (Docusaurus lo impide) — "unsupported modules".
// Y ojo con renombrar a middleware.mjs: el deploy queda VERDE y SIN
// middleware (la ausencia silenciosa del gate). Hallazgo del piloto
// odumbo-docs, deployment 3mXWLwPHPgcwasEji49pGEg7Lyuv.
import { decidir } from './node_modules/@ingadhoc/docs-platform/lib/mcp/gate.mjs';
const AUDIENCIAS = ['publico', 'interno']; // adhoc-docs: ['interno']
export default function middleware(request) {
return decidir(request, process.env, { audiencias: AUDIENCIAS }) ?? next();
}// package.json del consumidor — el guard, dentro del buildCommand
"build:publico": "node tools/build.mjs --audience=publico && npm --prefix site run build && npx docs-guard-fuga --salida=dist/publico"&& — не косметика: это то, что прерывает деплой, когда защитный механизм выходит с кодом 1. Не меняй его на ;.
Related MCP server: docrag
Что экспортирует
Импорт | Что это |
| поисковый движок: |
|
|
|
|
| сравнение токенов за постоянное время (использует |
| грамматика |
|
|
|
|
|
|
| эталонный |
bin | защитный механизм от утечек, для |
bin | drift-check, для CI потребителя |
Два контракта
Оба несут schemaVersion, и оба читателя выбрасывают ошибку, если эмитент объявляет более новую версию, чем они умеют читать — или если не объявляет её вообще. Никакой тихой деградации: неправильно отвечающий индекс хуже, чем тот, который не отвечает.
config ↔ платформа:
docs.config.json, со схемой, опубликованной вschema/docs.config.schema.json, и валидатором вlib/config.mjs(собственный, без зависимостей:ajvне попадает в сборку публичного сайта). Дизайн каждого поля с измеренными доказательствами находится вdocs/unificacion/diseno-eje.md; три текущих конфига в переводе — вmapeo-configs.md.индекс ↔ движок: его выдаёт
tools/build.mjsкаждого репозитория, а читаетlib/mcp/indice.mjs. Он описан вdocs/unificacion/contrato-indice.md.
Ось в таблице
Корпус объявляет одну ось как объект: { tipo, default?, valores[] }.
| корпус | параметр в tools |
| подстановочный знак (статьи вне оси) |
| oba-docs |
| выбирает | да ( |
| adhoc-docs |
| структурная неоднозначность (не объявляет | нет |
| odumbo-docs | (не раскрывается) | — | — |
Правило leer() одно и не содержит if по типу оси: оно выбирает только тогда, когда конфиг объявил, кого выбирать. Поведение меняет наличие eje.default, а не тип — и есть тест, который это проверяет, добавляя default корпусу с осью project.
Запуск тестов
npm install && npm test # 227 casosbloques требует репозиторий контента (он по-настоящему запускает его tools/build.mjs на фикстурах инцидентов) и пропускается с причиной, если его нет:
DOCS_REPO=~/repositorios/oba-docs node --test tests/bloques.test.mjsПолоса HTTP-обработчика из mcp.test.mjs (16 случаев) также пропускается с причиной, если в checkout нет mcp-handler/zod, которые являются зависимостями потребителя, а не этого пакета. С обеими установленными mcp даёт 57. Случай без своей capability пропускается явно; он не выполняется в деградированном режиме.
Для jjs — открытые решения
Что этот ансамбль не решает сам. Первые три — из diseno-eje.md §7 и затрагивают контракт; остальные вышли из четырёх анализов и остаются живыми после унификации.
1. Одна ось на корпус: принимается ли потолок?
schemaVersion: 1 допускает одну ось на конфиг, и сегодня этого достаточно для трёх репозиториев. В день, когда корпусу понадобится project × version одновременно, схема этого не выражает, и выход — schemaVersion: 2 с ejes: [...] (множественное число). Рекомендация дизайна: явно принять потолок и позволить реальной потребности переоткрыть его с доказательствами (тот же критерий, что и сигнализация о бампах на Этапе B). Это твоё решение, потому что оно затрагивает major.
2. metadata.types: словарь по корпусу или единый для Adhoc?
Сегодня только у adhoc-docs есть types, и его 6 значений очень похожи на стандарт из knowledge-management (concepto, referencia, procedimiento, troubleshooting, guia, indice). Если словарь принадлежит Adhoc, он не идёт в конфиг каждого репозитория: он идёт в пакет, а конфиг только говорит, требует ли он его. Это решение по управлению контентом, а не по схеме; пока оно не принято, схема оставляет его как список по корпусу (совместимо с обоими выходами).
3. Отказ от защитного механизма от утечек в adhoc-docs: подписываешь?
Схема обязывает объявлять deploy.guardDeFuga, так что тихое опущение больше невозможно. Остаются два выхода, оба защитимы: {"activo": false, "motivo": "…"} (у этого репозитория нет публичной сборки: его шлюз безусловный, а защитный механизм защищает от утечки в публичную сборку), или защитный механизм входит всё равно, как ремень. motivo, который сегодня находится в mapeo-configs.md, буквально гласит "PENDIENTE DE FIRMA (jjs)".
И есть техническая часть, которая не исправляется копированием файла (ВОПРОС 1 из analisis-04-seguridad.md): у adhoc-docs нет блоков :::interno, он не выдаёт site/generated.json с аудиторией и у него нет карты deploy.proyectos. С активным защитным механизмом как есть его сборка падает с самого начала из-за "no existe site/generated.json". Строгий вариант — чтобы он выдавал эти две вещи.
4. Список аудиторий остаётся дублированным, и drift-check пока его не сравнивает
docs.config.json → audiences и middleware.js → AUDIENCIAS должны совпадать, и нет способа избежать дублирования: edge не читает из файловой системы. Это ровно тот тип тихого дрейфа, с которого начался форк. Не хватает случая в CI, который бы их сравнивал (сегодняшний docs-drift-check измеряет пин, а не эту согласованность).
5. Три вещи, которые нужно проверить в репозиториях перед тегированием
DOCS_AUDIENCEво всех трёх окружениях каждого проекта Vercel (Production, Preview и Development) до merge, который принимает пакет. При fail-closed проект без переменной возвращает 503. Это безопасное направление, но не бесплатное.--esperadaв текущихbuildCommand: теперь защитный механизм отклоняет его при работе в Vercel. Если какой-то buildCommand передаёт его сегодня, этот деплой начнёт падать. Не удалось проверить по снимкам.GET MCP возвращает 503, если деплой не объявляет обслуживаемую аудиторию. Это наблюдаемое изменение для потребителя: предварительная проверка Claude Code получает 503 вместо плаката, когда деплой неправильно сконфигурирован.
6. Измеренный долг, который этот пакет не может закрыть
Fail-closed препроцессора выводит и затем завершается с ошибкой. С неправильно написанной директивой (
::: interno),build.mjsзаписываетsite/docs/**с внутренней строкой внутри и затем завершается с кодом 1. Сегодня утечки нет, потому чтоbuildCommandобъединяется через&&: защита находится в операторе, а не в программе. Оно объявлено какtodoвtests/bloques.test.mjs, и это исправляет унификацияbuild.mjs— которая не вошла в этот этап.tests/bloques.test.mjsзаписывает в<repo>/site/потому что в oba и odumbo выходные данные сборки захардкожены. После запуска набора тестов нужно перегенерировать с помощьюnpm run gen.Ограничения лексического подхода guard: числа и строки короче 5 символов никогда не имеют зонда (ключ
4821, аббревиатура), изображения не сканируются, и утечка внутриapplyBlocksне генерирует зонд. Это указано в заголовке guard; я повторяю это здесь, потому что эту часть можно спутать с покрытием.serverInfo.versionпо-прежнему захардкожена как'1.0.0'в обработчике. Она должна браться изpackage.jsonзакреплённого пакета, чтобы клиент MCP мог сообщить, с какой версией платформы он взаимодействовал. Это не изменено: это было бы выдумыванием поведения.Подстановочный знак является свойством
tipoоси, а не корпуса. Корпус с осьюprojectне может иметь поперечный документ (eje: nullостаётся невидимым для любого фильтра). Если когда-нибудь это понадобится, строгий выход — чтобы контракт индекса запрещал это, пока подстановочный знак выключен, чтобы противоречие возникало на этапе сборки, а не в рантайме.В спецификации сказано "vitest" как соглашение о тестах Этапа A, и ни один из трёх репозиториев не использует vitest: реальное соглашение — и соглашение этого пакета — это нативный
node:test. Стоит исправить эту строку, прежде чем кто-то установит vitest, чтобы ей соответствовать.
This server cannot be deployed
Maintenance
Related MCP Connectors
Team docs served to AI agents over MCP - search, Markdown reads, version pinning, read audit.
Read-only MCP server for the OrchestKit docs: full-text search + Markdown fetch. No auth.
Political Comms documentation MCP server: search docs, query the docs filesystem. No auth.
Public read-only MCP for products, frameworks, guides, methodology, and blog metadata.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceEnables MCP clients to access and read mdbook documentation, including structure, content, and search.12 npm3MIT
- AlicenseNot gradedqualityDmaintenanceProvides RAG (Retrieval Augmented Generation) access to technical documentation through MCP, enabling LLMs to search and retrieve relevant documentation on-demand.4MIT
- AlicenseNot gradedqualityAmaintenanceEnables searching, reading, and navigating MkDocs documentation sites through MCP tools for keyword, semantic, or hybrid search, document browsing, and project metadata.1BSD 2-Clause "Simplified"
- FlicenseAqualityCmaintenanceEnables MCP clients to retrieve authoritative AI Square documentation, API references, SDK examples, guides, and troubleshooting information through citation-safe hybrid search and static resources.11-