Skip to content

fix(docs): apply non-public folder exclusion on runtime /docs route (#1794)#1799

Merged
markmhendrickson merged 3 commits into
mainfrom
claude/frosty-lichterman-bb4839
Jun 25, 2026
Merged

fix(docs): apply non-public folder exclusion on runtime /docs route (#1794)#1799
markmhendrickson merged 3 commits into
mainfrom
claude/frosty-lichterman-bb4839

Conversation

@markmhendrickson

Copy link
Copy Markdown
Owner

Closes #1794.

Problems

The in-app /docs route served a different surface depending on deployment mode:

Root cause: the public-surface curation lived in two places that disagreed. The build-time bundler (scripts/build_bundled_docs.ts) applied an EXCLUDED_TOP folder set; the runtime route (buildDocsIndex, lookupDoc) applied only the per-file isVisible gate. Because FOLDER_DEFAULTS marks releases/feature_units as visibility: public, the runtime kept them.

Solutions

Hoist the exclusion into a single shared predicate, applied on all three paths:

  • Add NON_PUBLIC_TOP_FOLDERS + isNonPublicTopFolder() to src/services/docs/visibility.ts (single source of truth).
  • buildDocsIndex (index_builder.ts) and lookupDoc (render.ts) drop non-public top folders unless show-internal is enabled. Default (production) now matches the curated npm bundle; NEOTOMA_DOCS_SHOW_INTERNAL=true reveals the full checkout tree for local dev.
  • build_bundled_docs.ts imports the shared set instead of its duplicated local copy.

site/ is a packaging exclusion, not a surface exclusion

site/ (the marketing-site pages) is intentionally not in the shared set. The root-landing footer (bundled_nav.ts) links into site/pages/en/* (Install, API, FAQ, Privacy, Terms), and those are served on from-source hosts. The npm bundle still drops site/ (the package ships .md docs only, not the marketing tree), so the bundler adds site to its own BUNDLE_EXCLUDED_TOP on top of the shared set. This keeps the bundle output byte-identical (359 docs) while preserving the landing footer on from-source hosts.

Behavior change

On hosted-from-source instances, /docs and /docs/<slug> for excluded folders (releases/*, feature_units/*, plans/*, ...) now 404 by default, matching what npm installs already do. Set NEOTOMA_DOCS_SHOW_INTERNAL=true to browse the full tree. No change for npm installs; site/ browsing on from-source hosts is unchanged.

Test plan

  • npm run type-check — clean.
  • Docs + nav suites green (87 tests): src/services/docs/**, tests/integration/docs_route.test.ts, tests/unit/bundled_docs_nav.test.ts (7/7).
    • New: index_builder.test.ts (non-public folders filtered by default, shown with NEOTOMA_DOCS_SHOW_INTERNAL=true), render.test.ts (excluded-folder direct lookup hidden by default), visibility.test.ts (isNonPublicTopFolder + set/predicate sync; site is not excluded).
  • Bundler re-run: still copies 359 public docs (output unchanged).
  • npm run lint (0 errors), format:check, lint:site-copy, validate:doc-deps — all pass.

Note: the local pre-commit hook's full unit+integration suite was skipped via the hook-sanctioned NEOTOMA_SKIP_TESTS=1 (not --no-verify) because this worktree has unrelated failures — the inspector SPA-shell tests deterministically fail ("No bundled SPA found", Inspector not built here) and a few DB tests are parallel-SQLite-flaky (verified green in isolation: deletion.test.ts, mcp_entity_variations.test.ts). All non-test gates above still ran. CI runs the full suite on this PR.

…1794)

The in-app /docs route served a different surface depending on deployment
mode: npm installs got the curated public bundle, but hosted-from-source
instances served the entire docs/ checkout tree (release history, feature
units, internal process folders), because the EXCLUDED_TOP curation lived only
in the build-time bundler. FOLDER_DEFAULTS marks releases/feature_units as
public, so the runtime isVisible gate kept them.

Hoist the exclusion into a single shared predicate applied on all three paths:

- Add NON_PUBLIC_TOP_FOLDERS + isNonPublicTopFolder() to visibility.ts.
- buildDocsIndex and lookupDoc drop non-public top folders unless show-internal
  is set: the default (production) now matches the curated npm bundle;
  NEOTOMA_DOCS_SHOW_INTERNAL=true reveals the full tree for local dev.
- build_bundled_docs.ts imports the shared set; the bundle additionally drops
  site/ as a packaging concern (npm ships .md docs only, not the marketing
  tree). site/ stays browsable on from-source hosts because the root-landing
  footer links into site/pages/en/*, so it is NOT in the shared surface set.

Behavior change: on from-source hosts, /docs and /docs/<slug> for excluded
folders (releases/*, feature_units/*, ...) now 404 by default, matching npm.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@neotoma-agent

Copy link
Copy Markdown
Collaborator

review:pm

🤖 Pavo — Ateles swarm, pm lens panelist
APPROVE

Review Summary

PR implements exactly what the pm gate signed off on #1794. All five acceptance criteria satisfied:

  • Shared predicate isNonPublicTopFolder() defined in src/services/docs/visibility.ts and applied consistently to buildDocsIndex, lookupDoc, and the bundler (scripts/build_bundled_docs.ts).
  • On hosted-from-source instances, /docs/<slug> for excluded folders returns 404 by default; resolves under NEOTOMA_DOCS_SHOW_INTERNAL=true.
  • Bundled npm docs remain unconditionally curated (no behavior change for npm users; bundler output is identical byte count: 359 docs).
  • Test coverage added: index_builder.test.ts verifies exclusion by default and inclusion under show-internal flag; render.test.ts verifies direct lookup behavior plus the new "hidden" error kind for non-public folders.
  • No unrequested scope creep (no new config flags, visibility UI changes, or doc restructuring).

Scope Validation

In scope:

  • Runtime route exclusion via shared predicate
  • Visibility gating by NEOTOMA_DOCS_SHOW_INTERNAL
  • Test coverage for both paths
  • Bundler parity (shared set applied)

Out of scope (not attempted, correctly):

  • New config flags or override mechanisms
  • Visibility UI changes or preference surfaces
  • Doc restructuring or folder reorganization
  • Changes to npm install behavior

Behavior Alignment

Default production behavior now matches curated npm bundle surface on from-source instances. Local dev with NEOTOMA_DOCS_SHOW_INTERNAL=true reveals full checkout tree. 🎯

PM gate sign-off: Criteria met. Ready for merge.


📎 Neotoma: issue #1794

@neotoma-agent

Copy link
Copy Markdown
Collaborator

review:ux
🤖 Accipiter — Ateles swarm, ux lens panelist
COMMENT

The PR improves consistency between npm-bundled and hosted-from-source instances by applying folder-level visibility filtering uniformly. The code surface is clear — naming, error types, and the shared predicate (isNonPublicTopFolder) follow good patterns. Three observations:

[NON-BLOCKING] Behavioral change: 404 on excluded folders needs operator guidance

This PR changes deployed behavior on hosted-from-source instances: URLs like /docs/releases/v2.5.0/changes.md that previously resolved now return 404 by default. The environment opt-in NEOTOMA_DOCS_SHOW_INTERNAL=true re-enables the full tree.

UX concern: operators on live instances won't discover this behavior change or the opt-in without digging into the PR body or release notes. The visibility.ts comments explain the toggle well for developers reading the code, but there's no user-facing path to discover "why did my old doc URL break?" or "how do I restore it?"

Severity: P2 (non-blocking; this is primarily a self-service docs host, and the PR body documents the change clearly for a first reading). But consider:

  • A brief CHANGELOG.md or release-notes entry flagging the behavior change + the env var would bridge the gap.
  • If live Neotoma instances are affected, ops should know the opt-in flag exists before the deploy.

[NON-BLOCKING] Error discriminator: hidden vs not_found inconsistency

The DocLookupError type distinguishes between not_found and hidden, but both return HTTP 404 to clients. The HTTP layer (not shown in this PR) will treat them identically.

Benefit of the current design: internal logging can distinguish between "the file truly doesn't exist" and "the file exists but was filtered." This is useful for debugging.

Consideration: ensure the HTTP handler logs the hidden case — otherwise operators won't know whether a 404 is a real missing file or a visibility filter. If that logging already exists upstream, this is fine; if not, flag it as a follow-up.

[NON-BLOCKING] Documentation for developers: is the env var testable?

The comments explain NEOTOMA_DOCS_SHOW_INTERNAL=true clearly, and the tests cover both the default (hidden) and opt-in (shown) paths. Good test coverage.

Minor: the in-code comment in visibility.ts says "on the runtime route the exclusion is gated by show-internal" — but it's also gated in index_builder (the /docs listing), which is the first discovery point for most users. The phrasing could tighten to: "The exclusion applies throughout the runtime: index building, direct lookup, and the bundler." (Nitpick; the comment is already detailed.)


Verdict summary:

  • ✅ Single source of truth for folder exclusions eliminates the consistency bug (strong improvement).
  • ✅ Naming is discoverable and clear.
  • ✅ Tests cover both happy and opt-in paths.
  • ⚠️ Behavior change on live instances needs brief release-notes callout so operators know the flag exists.
  • ⚠️ Ensure the 404 handler logs whether the error is hidden vs not_found for ops visibility.

No blockers for merge. The UX patterns are sound; the two concerns are release/ops comms (outside code scope) and a minor logging recommendation for the HTTP handler.

@neotoma-agent

Copy link
Copy Markdown
Collaborator

review:legal
🤖 Buteo — Ateles swarm, legal lens panelist
APPROVE

Compliance Checklist

  • Dependencies/licensing: No new npm or build dependencies added. Only internal TypeScript imports (visibility.js, doc_frontmatter.js). All existing dependencies remain compatible.
  • Secrets/PII surface: No credential, API token, or PII exposure. Excluded folders are markdown documentation only (release history, feature units, plans, internal processes). Error responses use only "hidden" and "not_found" kinds without exposing path details or configuration.
  • Data-handling: No new data ingestion, processing, or handling paths. Public docs remain appropriate for unauthenticated guest access. Default behavior in production is now stricter (excludes more folders), improving compliance posture by preventing unintended exposure of internal-process documentation.
  • ToS/legal exposure: Shared isNonPublicTopFolder() predicate properly gates excluded folders based on NEOTOMA_DOCS_SHOW_INTERNAL flag. Bundler and runtime route now use the same set (NON_PUBLIC_TOP_FOLDERS), maintaining parity. Behavioral change (404 for excluded folders by default on hosted-from-source) is intentional, documented in the PR description, and matches npm-install behavior.

Findings

  • Compliance improvements: Default production behavior now excludes release history, feature units, plans, and internal-process trees from the public /docs surface, reducing exposure of internal documentation unless explicitly opted in via NEOTOMA_DOCS_SHOW_INTERNAL=true.
  • Parity validated: Bundler output verified unchanged (359 public docs). From-source and npm-install surfaces now match by default.
  • No blocking concerns: All legal expectations met.

📎 Neotoma: issue markmhendrickson/neotoma#1794

@neotoma-agent

Copy link
Copy Markdown
Collaborator

review:qa
🤖 Phoenicurus — Ateles swarm, qa lens panelist

APPROVE

Summary

The fix hoists a per-deployment visibility inconsistency into a single shared predicate (NON_PUBLIC_TOP_FOLDERS + isNonPublicTopFolder()) applied on all three docs-serving paths: runtime index builder, runtime slug lookup, and build-time bundler.

Bug fixed: On from-source deployments, /docs and /docs/<slug> served the full docs/ checkout tree (releases/, feature_units/, plans/, etc.), while npm-installed packages showed the curated bundle. This mismatch created an inconsistency where operators could browse internal-process folders in production unless NEOTOMA_DOCS_SHOW_INTERNAL=true.

Behavior change (intentional): From-source hosts now default to the curated public surface and require the flag to reveal the full tree, matching the npm bundle behavior.

Test Coverage

Edge Cases & Assertions

Non-public folder exclusion (production default):

  • index_builder.test.ts: "excludes non-public top folders by default" — verifies releases/v1 is dropped from the index
  • render.test.ts: "hides a public doc in a non-public top folder by default" — verifies direct slug lookup returns error kind hidden (not not_found)
  • visibility.test.ts: "matches paths under non-public top folders" — asserts releases/in_progress/, feature_units/, plans/ paths return true

Flag override (show-internal):

  • index_builder.test.ts: "includes non-public top folders with the show-internal flag" — verifies NEOTOMA_DOCS_SHOW_INTERNAL=true restores releases/ to the index
  • render.test.ts: "shows a non-public top folder doc with show-internal flag" — verifies the doc renders when flag is set
  • Integration test docs_route.test.ts does NOT cover the new releases/ or feature_units/ filtering but DOES cover the existing plans/ exclusion (also in NON_PUBLIC_TOP_FOLDERS)

Boundary cases:

  • visibility.test.ts: "does not match public-surface folders or top-level files" — foundation/, getting_started/, MANIFEST.md return false
  • Note: site/ is intentionally NOT in the shared set (bundler-only exclusion); test asserts isNonPublicTopFolder("site/pages/en/...") returns false ✓

Predicate invariant:

  • visibility.test.ts: "keeps the set and predicate in sync" — verifies every entry in NON_PUBLIC_TOP_FOLDERS matches true when tested with isNonPublicTopFolder()

Regression Test: The Original Bug

The fix corrects a logic flaw: FOLDER_DEFAULTS marks releases/ and feature_units/ as visibility: public (they contain user-readable release notes and specs). The original runtime code called isVisible() at the file level, which returned true, so the folders appeared in the index and were slug-resolvable on from-source hosts.

The new test index_builder.test.ts → "excludes non-public top folders by default" directly asserts the fix: It verifies that releases/v1.md (which would pass isVisible() per FOLDER_DEFAULTS) is now filtered out at the top-folder level before the per-file visibility check runs. This prevents the regression.

Integration surface: docs_route.test.ts does not yet test GET /docs/releases/* or GET /docs/feature_units/* by default (the IT uses only plans/draft, which already had per-file visibility: internal). However, the unit tests on index_builder and render are sufficient to catch a regression in the predicate logic itself.

[NON-BLOCKING] Code coverage gap: The integration test should add explicit assertions for GET /docs/releases/v0.17.0 (or similar) returning 404 in production, and 200 with the flag set. This would provide end-to-end verification that the shared predicate is correctly wired into the route handler. Current unit test coverage is solid; the integration test addition would raise confidence to maximum.

Shared Predicate Correctness

build_bundled_docs.ts now imports NON_PUBLIC_TOP_FOLDERS and uses it to build BUNDLE_EXCLUDED_TOP, with site/ added only for the bundler (per-design). Coupling is correct: the shared set is the canonical list, the bundler extends it.

✅ No per-type branches or hardcoded path lists introduced — the solution follows schema-agnostic design rules.

Contract & CLI/MCP Parity

This is a docs-route visibility fix, not an API/MCP/CLI surface change. No openapi.yaml, contract mapping, or CLI instruction updates required.


Verdict: Test coverage is adequate for the functional change. The unit tests directly assert the bug is fixed (non-public folders excluded by default, included with flag). Integration test coverage is optional but recommended (does not block merge).

@neotoma-agent

Copy link
Copy Markdown
Collaborator

🤖 Vanellus — Ateles swarm, PR steward
APPROVE

Aggregated Review Verdict — PR #1799

Per-Lens Summary

PM (Pavo):APPROVE

  • All five acceptance criteria satisfied: shared predicate defined, runtime exclusion gating, bundler parity, test coverage, no scope creep.
  • Spec compliance confirmed.

UX (Accipiter):COMMENT (non-blocking)

  • Code quality and naming excellent; single source of truth eliminates consistency bug.
  • Two non-blocking observations:
    1. Behavior change (404 on excluded folders by default) needs release-notes callout for operators + environment opt-in documentation.
    2. Ensure HTTP handler logs hidden vs not_found distinction for ops visibility (logging is outside this PR's scope).
  • No blockers for merge.

Legal (Buteo):APPROVE

  • No new dependencies, secrets, or PII exposure.
  • Compliance improvements: default production behavior now stricter (excludes internal documentation unless explicitly opted in).
  • Parity validated: bundler output unchanged (359 public docs), from-source and npm-install surfaces now match by default.

QA (Phoenicurus):APPROVE

  • Adequate unit test coverage: index_builder.test.ts, render.test.ts, visibility.test.ts directly assert the bug is fixed (non-public folders excluded by default, included with flag).
  • Shared predicate correctness verified; site/ correctly excluded only in bundler.
  • Non-blocking: integration test could add end-to-end assertions for /docs/releases/* 404 behavior (recommended but not required for merge).
  • No blockers.

CI Status

  • security_gates: SUCCESS
  • frontend: SUCCESS
  • python_sdk: SUCCESS
  • agentic_evals: SUCCESS
  • eval_scenarios: SUCCESS
  • eval_combined: SUCCESS
  • ⚠️ baseline: FAILURE (advisory, not required by branch protection)
  • site_export: IN_PROGRESS (advisory, not required by branch protection)

Required branch-protection checks: security_gates ✅ SUCCESS. PR is check-ready.

Blockers

None. All four panel lenses clear or non-blocking.

Merge Readiness

Recommendation: Ready for merge. Merge is operator-gated; operator to confirm before proceeding.


📎 Neotoma: issue #1794 · PR markmhendrickson/neotoma#1799

@neotoma-agent

Copy link
Copy Markdown
Collaborator

review:pm
🤖 Pavo — Ateles swarm, pm lens panelist
APPROVE

All acceptance criteria from the pm gate sign-off on issue #1794 are met.

✅ Shared Predicate Defined and Applied Consistently

visibility.ts: NON_PUBLIC_TOP_FOLDERS (ReadonlySet) and isNonPublicTopFolder(relPath: string) defined as single source of truth. Clear comment explaining site/ is a packaging exclusion (bundler-only), not a surface exclusion.

render.ts (lookupDoc): Imports the shared predicate; guards direct slug lookup with if (!shouldShowInternal(env) && isNonPublicTopFolder(relFromRoot)) return { ok: false, error: { kind: "hidden" } }.

index_builder.ts (buildDocsIndex): Filters non-public folders during index build: if (!showInternal && isNonPublicTopFolder(rel)) continue;.

build_bundled_docs.ts (bundler): Removes hardcoded EXCLUDED_TOP; imports and reuses NON_PUBLIC_TOP_FOLDERS, adding site locally for npm-only exclusion.

No duplication. Single source of truth applied consistently on all three paths.

✅ Hosted-from-Source Returns 404; show-internal Flag Works

Direct lookups return { kind: "hidden" } when a non-public folder doc is requested without the flag. Non-public folders are dropped from the index by default; setting NEOTOMA_DOCS_SHOW_INTERNAL=true includes them.

Behavior matches expectation: 404 by default on from-source, full tree under flag.

✅ npm Bundle Behavior Unchanged

BUNDLE_EXCLUDED_TOP adds site on top of the shared set. Bundler applies unconditionally (no show-internal flag). Test plan confirms output remains 359 public docs (byte-identical).

npm installs are unaffected.

✅ Test Coverage: Exclusion by Default, Inclusion Under Flag

visibility.test.ts: Unit tests for isNonPublicTopFolder predicate; sync check iterates set and confirms all members; confirms site is NOT in the shared set.

index_builder.test.ts: New tests verify releases folder excluded by default, included with NEOTOMA_DOCS_SHOW_INTERNAL=true.

render.test.ts: New tests verify direct lookup of non-public docs returns { kind: "hidden" } by default, resolves with flag.

Test coverage explicit and comprehensive.

✅ No Scope Creep

No new env flags, UI changes, doc restructuring, or schema changes. Error handling reuses existing hidden kind.


Verdict: All pm gate acceptance criteria met. Implementation is focused, well-tested, and matches the scoped intent. Ready for merge.

@neotoma-agent

Copy link
Copy Markdown
Collaborator

review:ux
🤖 Accipiter — Ateles swarm, ux lens panelist
COMMENT

User-facing surface

New runtime environment variable: NEOTOMA_DOCS_SHOW_INTERNAL=true toggles visibility of non-public docs folders (releases/, feature_units/, plans/, proposals/, prototypes/, reports/, implementation/, private/, assets/, templates/, research/). Production default (unset) hides them; local dev can reveal them.

New error state: direct slug lookup (e.g., /docs/releases/v1-changelog) returns error.kind: "hidden" when the doc is in a non-public folder and the flag is not set. Distinguishes from not_found (file doesn't exist).

Behavior change: On hosted-from-source instances, URLs to excluded folders now 404 (by default). No change for npm installs (already filtered).

Interaction / flow

  1. Discovery via /docs index — Non-public folders are excluded from the category index by default; NEOTOMA_DOCS_SHOW_INTERNAL=true includes them.
  2. Direct slug lookup — Attempting /docs/<slug> in a non-public folder returns error.kind: "hidden" (production) or renders normally (with flag).
  3. Flag enable — Developer sets env var and restarts; behavior changes immediately.

Discoverability & naming

Strengths:

  • NON_PUBLIC_TOP_FOLDERS constant name is explicit and IA is clear (top-level folders, not public).
  • isNonPublicTopFolder() function name matches the pattern of existing isVisible().
  • NEOTOMA_DOCS_SHOW_INTERNAL=true naming mirrors the existing shouldShowInternal() predicate.
  • Comment in visibility.ts clearly explains the distinction between surface exclusion (folders) vs. packaging exclusion (site/), with a note about why site/ is intentionally not in the shared set.

Friction point — The error kind "hidden" is a new term introduced here. Reviewers and implementers will need to trace back to render.ts to understand what "hidden" means and how it differs from "not_found" in downstream HTTP handling. No blocking issue if the HTTP route that consumes this error already handles both kinds distinctly (200 vs 404), but the error type adds a branch in the call graph that wasn't there before. Confirm that the route handler (/api/docs/<slug> or similar) actually differentiates these two error kinds, or they collapse to the same HTTP status anyway.

Error & empty states

✓ Non-existent files return error.kind: "not_found".
✓ Files in non-public folders (flag unset) return error.kind: "hidden".
✓ Files in non-public folders (flag set) render normally.
✓ Index excludes non-public categories by default; includes them with flag.
✓ Index index builder and slug lookup are gated consistently.

Tests cover all three states and both code paths (flag on/off). Good coverage.

Accessibility

N/A — backend-only docs-serving logic, no user-facing UI.

Acceptance checklist

  • Single source of truth (NON_PUBLIC_TOP_FOLDERS) shared by runtime and bundler.
  • Naming is consistent (isNonPublicTopFolder, NEOTOMA_DOCS_SHOW_INTERNAL).
  • Error states distinguish hidden vs. not-found (though downstream HTTP handler must be verified).
  • Tests cover happy path, flag-enabled path, and default-hidden path.
  • Comment clearly explains the site/ exception and why it's not in the shared set.
  • Env var convention matches existing shouldShowInternal() pattern.

Verdict

COMMENT — The UX surface is clean and naming is consistent with existing patterns. The new "hidden" error kind is a minor addition that requires verification downstream (confirm that the HTTP route handler for /docs/<slug> actually differentiates hidden from not_found and maps them appropriately; if they both become 404, then the error kind is internal implementation detail and no action needed). No blocking UX issues.

@neotoma-agent

Copy link
Copy Markdown
Collaborator

review:legal
🤖 Buteo — Ateles swarm, legal lens panelist
APPROVE

Legal Surface Review — PR #1799

Findings

  • No new npm/build dependencies: package.json unchanged; only imports from existing codebase (visibility.js, fs, path). ✓
  • No credential, API token, or PII exposure: Changes gate which folders are served, not content parsing. Non-public folders (releases, feature_units, plans, proposals, etc.) excluded entirely via isNonPublicTopFolder() predicate. Private folder handling remains intact. Error kind ("hidden") is generic. ✓
  • Shared visibility predicate properly gates exclusion: isNonPublicTopFolder() enforced on both runtime index builder (index_builder.ts) and direct slug lookup (render.ts). NEOTOMA_DOCS_SHOW_INTERNAL flag controls disclosure in production (default: exclude) vs. local dev (flag: include). ✓
  • Behavioral changes intentional and documented: PR body explicitly states 404 behavior for excluded folders is intentional, documented default. No silent data exposure. ✓
  • Bundler exclusion parity maintained: scripts/build_bundled_docs.ts imports shared NON_PUBLIC_TOP_FOLDERS constant; BUNDLE_EXCLUDED_TOP = new Set([...NON_PUBLIC_TOP_FOLDERS, "site"]). Bundler output remains 359 docs, npm bundle remains unconditionally public. ✓
  • No regression in regulatory/data-handling compliance: Public docs remain appropriate for guest access (per-file isVisible check still applies). From-source production instance now matches npm install surface by default (favorable consistency). Show-internal is runtime dev toggle, not a shipped feature. ✓

Test Coverage

  • visibility.test.ts — set/predicate sync confirmed; site correctly confirmed as not in non-public set (packaging exclusion only).
  • index_builder.test.ts — excludes releases by default; includes with flag.
  • render.test.ts — slug lookup returns "hidden" error for excluded folders; shows with flag.

All pre-registered expectations satisfied.


📎 Neotoma: markmhendrickson/neotoma#1794

@neotoma-agent

Copy link
Copy Markdown
Collaborator

review:qa
🤖 Phoenicurus — Ateles swarm, qa lens panelist

APPROVE

Summary

This PR fixes a deployment-mode surfacing bug in the /docs route by hoisting folder exclusions from build-time bundler to runtime, then gates them with NEOTOMA_DOCS_SHOW_INTERNAL. Coverage is complete: unit tests on the new predicate, integration tests on both affected code paths (index builder and slug lookup), edge cases on the site/ packaging-only exclusion, and the bundle sync behavior.

Eval Coverage

New coverage added — all passing:

  1. src/services/docs/visibility.test.ts:

    • isNonPublicTopFolder() unit tests (3): matches paths under exclusion set, rejects public folders and top-level files, verifies set/predicate parity.
  2. src/services/docs/index_builder.test.ts:

    • Integration test "excludes non-public top folders by default" — asserts that buildDocsIndex drops non-public folders from the index in production.
    • Integration test "includes non-public top folders with the show-internal flag" — asserts that show-internal env var includes them.
  3. src/services/docs/render.test.ts:

    • Integration test "hides a public doc in a non-public top folder by default" — asserts that lookupDoc("releases/changelog") returns hidden in production.
    • Integration test "shows a non-public top folder doc with show-internal flag" — asserts that same slug renders when flag is set.

Coverage quality:

  • Happy path: ✓ default exclusion works in production
  • Flag path: ✓ both code paths (index builder + slug lookup) respect show-internal
  • Edge case: ✓ site/ packaging exclusion is tested (intentionally excluded from NON_PUBLIC_TOP_FOLDERS, only dropped by bundler)
  • Error case: ✓ distinction between "not_found" and "hidden" errors tested (lines 101–103, render.test.ts)
  • Behavior change regression: ✓ prior tests for internal-visibility frontmatter still pass; new tests confirm the folder-level exclusion is independent of per-doc visibility

Test runs green:

  • All 67 tests in src/services/docs/ pass (visibility, index_builder, render, markdown_render, manifest_loader, doc_frontmatter, docs_root).
  • Bundle build succeeds: [bundle-docs] copied 359 public docs to dist/docs (skipped 12 internal, 0 deprecated).

Determinism

Data-layer behavior is deterministic:

  • NON_PUBLIC_TOP_FOLDERS is a frozen ReadonlySet; contents hard-coded.
  • isNonPublicTopFolder() is stateless, deterministic path lookup via .split("/")[0].
  • Index and render functions produce the same output on repeated runs (verified by existing "returns a deterministic tree across runs" test at line 127–131, index_builder.test.ts).

Functional surface

Agent-observable effects asserted:

  • Slug lookup now returns { ok: false, error: { kind: "hidden" } } for non-public-folder docs when show-internal is off. Prior behavior: depended on per-doc visibility frontmatter or folder-level FOLDER_DEFAULTS (inconsistent between npm-bundled and from-source hosts). New: both now match.
  • Index builder now excludes non-public top-folder entries from the category tree when show-internal is off.
  • npm bundle behavior unchanged: NON_PUBLIC_TOP_FOLDERS is imported and applied unconditionally by the bundler.

Breaking change:

  • From-source hosts now 404 requests to /docs/<slug> for excluded-folder slugs (e.g. /docs/releases/v1) in production by default. This matches npm bundle behavior. Users who want to expose internal docs must set NEOTOMA_DOCS_SHOW_INTERNAL=true explicitly.

Non-blocking observations

None. The change is well-scoped, backward-compatible via flag, and hardening (fails closed).

@neotoma-agent

Copy link
Copy Markdown
Collaborator

🤖 Vanellus — Ateles swarm, PR steward
APPROVE

Aggregated Review Verdict — PR #1799

Per-Lens Summary

PM (Pavo):APPROVE

  • All five acceptance criteria satisfied: shared predicate defined, runtime exclusion gating, bundler parity, test coverage, no scope creep.
  • Spec compliance confirmed.

UX (Accipiter):COMMENT (non-blocking)

  • Code quality and naming excellent; single source of truth eliminates consistency bug.
  • Two non-blocking observations:
    1. Behavior change (404 on excluded folders by default) needs release-notes callout for operators + environment opt-in documentation.
    2. Ensure HTTP handler logs hidden vs not_found distinction for ops visibility (logging is outside this PR's scope).
  • No blockers for merge.

Legal (Buteo):APPROVE

  • No new dependencies, secrets, or PII exposure.
  • Compliance improvements: default production behavior now stricter (excludes internal documentation unless explicitly opted in).
  • Parity validated: bundler output unchanged (359 public docs), from-source and npm-install surfaces now match by default.

QA (Phoenicurus):APPROVE

  • Adequate unit test coverage: index_builder.test.ts, render.test.ts, visibility.test.ts directly assert the bug is fixed (non-public folders excluded by default, included with flag).
  • Shared predicate correctness verified; site/ correctly excluded only in bundler.
  • Non-blocking: integration test could add end-to-end assertions for /docs/releases/* 404 behavior (recommended but not required for merge).
  • No blockers.

CI Status

  • security_gates: SUCCESS
  • frontend: SUCCESS
  • python_sdk: SUCCESS
  • agentic_evals: SUCCESS
  • eval_scenarios: SUCCESS
  • eval_combined: SUCCESS
  • ⚠️ baseline: FAILURE (advisory, not required by branch protection)
  • site_export: IN_PROGRESS (advisory, not required by branch protection)

Required branch-protection checks: security_gates ✅ SUCCESS. PR is check-ready.

Blockers

None. All four panel lenses clear or non-blocking.

Merge Readiness

Recommendation: Ready for merge. Merge is operator-gated; operator to confirm before proceeding.


📎 Neotoma: issue #1794 · PR markmhendrickson/neotoma#1799

@markmhendrickson markmhendrickson merged commit d72e27c into main Jun 25, 2026
8 of 9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

/docs serves full checkout tree on hosted-from-source instances (diverges from npm public bundle)

3 participants