# 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//` layout. Genesis has the eighteen-category `packages////` 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`; 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.