Files
2026-05-27 23:29:53 +01:00

6.1 KiB

Change: enterprise-docs

  • Package: @suaveplan/docs
  • Status: PROPOSED
  • Design: ./design.md
  • Spec delta: ./specs/docs/spec.md
  • Upstream: ../suaveplan/packages/universal/docs (1.0.3)
  • Enterprise audit: ../suaveplan/enterprise/docs.md

Why

Genesis is migrating @suaveplan/docs from the legacy packages/universal/docs/ checkout into the canonical packages/devtools/docs/docs/ location at enterprise quality. The upstream shipped a working markdown discovery + graph + hierarchy + search toolkit (~430 LOC of source plus tests), but the enterprise audit flagged gaps that block production use:

  1. Hand-crafted Error paths with no @suaveplan/error integration, no stable error-code registry, and no code field for programmatic discrimination.
  2. No OpenTelemetry instrumentation — operators cannot measure discovery / graph-build / search latency, doc-count volume, or error rate.
  3. No Zod validation at the DiscoverOptions boundary; bad arguments fail with glob's native error message rather than a typed DocsError.
  4. Silent failure mode in discoverDocs: unreadable files are swallowed with a bare catch {} — there is no way for operators to observe a permission / IO error rate.
  5. The parseDoc implementation casts to any (node as any) to navigate the mdast tree, defeating type-safety.
  6. No AbortSignal propagation through discoverDocs (the only long-running async entrypoint), so callers cannot cancel a sweep of a large monorepo.
  7. The DocCategory union is closed to the upstream six-category packages/<tier>/ layout. Genesis has the eighteen-category packages/<category>/<plugin>/<pkg>/ layout, so the upstream derivation produces "root" for every genesis package.

The greenfield rewrite addresses every gap while preserving the upstream public surface (discoverDocs, buildGraph, findOrphans, buildHierarchy, parseDoc, searchDocs, DiscoverOptions, DocCategory, DocFile, DocGraph, DocLink, DocNode, SearchResult, OrphanInfo, DocHierarchy) so downstream consumers continue to compile against the same import paths.

What changes

  • Add: @suaveplan/docs at version 0.1.0 under packages/devtools/docs/docs/ with full enterprise surface — typed errors via @suaveplan/error, OTel counters + histograms, Zod-validated DiscoverOptions, AbortSignal propagation, typed mdast traversal via @types/mdast, eighteen-category genesis DocCategory union, IO-error surfacing in discoverDocs, and per-feature subpath exports.
  • Add: error-code namespace DOCS.* with eight stable codes via defineCodes("DOCS", [...] as const): INVALID_OPTIONS, READ_FAILED, PARSE_FAILED, GLOB_FAILED, ABORTED, LINK_RESOLUTION_FAILED, HIERARCHY_CYCLE_LIMIT, SEARCH_INVALID_QUERY.
  • Add: OTel instruments — counters docs_discovered_total, docs_parse_error_total, docs_io_error_total, docs_search_total and histograms docs_discover_duration_ms, docs_parse_duration_ms, docs_graph_build_duration_ms, docs_search_duration_ms.
  • Add: subpath exports per feature module (./discovery/discover, ./parser/parse, ./graph/build-graph, ./graph/find-orphans, ./hierarchy/build-hierarchy, ./search/search, ./errors/errors, ./observability/observability, ./types).

Impact

Affected dependents

Run bunx turbo ls --filter=...@suaveplan/docs to enumerate.

  • No dependents (verified by bunx turbo ls --filter=...@suaveplan/docs).

Future doc-site consumers (api-docs, react-docs) will adopt this package via follow-up changes once they migrate; no work is required in this proposal.

Parity Checklist

Capability Upstream Migrated Notes
discoverDocs(options) ✅ ⬆️ Now Zod-validates options; surfaces IO errors via DOCS.READ_FAILED counter; honours AbortSignal; emits docs_discover_duration_ms.
parseDoc(absPath, relPath, raw) ✅ ⬆️ Now uses typed mdast Heading/Link nodes via @types/mdast; no as any; emits docs_parse_duration_ms histogram; counter docs_parse_error_total on frontmatter failure.
buildGraph(docs) ✅ ⬆️ Same shape; emits docs_graph_build_duration_ms. Genesis category awareness in orphan filter (root-tier docs still exempt).
findOrphans(graph) ✅ ✅ Same shape; sort key unchanged.
buildHierarchy(graph, options?) ✅ ⬆️ Same shape; cycle limit now configurable via maxDepth option (default 8 preserved).
searchDocs(docs, query, limit?) ✅ ⬆️ Same shape; emits docs_search_total + docs_search_duration_ms.
DocFile, DocLink, DocGraph, DocNode, DocHierarchy, DiscoverOptions, SearchResult, OrphanInfo ✅ ✅ Re-exported from ./types.
DocCategory union ✅ ⬆️ Extended from six (upstream tiers) to the eighteen-category genesis vocabulary so genesis packages classify correctly.
Typed errors with DOCS.* codes 🚫 ⬆️ NEW — DocsError extends SuaveplanError<DocsErrorCode>; all error paths use codes; error-code registry exported.
OTel counters + histograms 🚫 ⬆️ NEW — eight instruments wired into every public method.
Zod-validated options 🚫 ⬆️ NEW — DiscoverOptionsSchema enforces rootDir: string, ignore: string[]?, includeApps: boolean?, signal: AbortSignal?.
AbortSignal propagation 🚫 ⬆️ NEW — discoverDocs checks signal.aborted between glob and parse, and surfaces DOCS.ABORTED.
Genesis 18-category awareness 🚫 ⬆️ NEW — deriveCategory recognises every category in scripts/folder-reorg/assignment.yml.

Migration

This is a 0.1.0 first landing — no prior genesis consumers. Downstream waves that adopted the upstream surface from ../suaveplan/packages/universal/docs should:

  1. Update imports from @suaveplan/docs (path stays the same).
  2. Treat DocsError as the canonical thrown type; switch on error.code against DOCS_CODES.* rather than parsing error.message.
  3. Adopt AbortSignal on discoverDocs for cancellable scans of large monorepos.