Skip to content

docs: add a landing README and searchable reference site - #89

Open
lan17 wants to merge 22 commits into
mainfrom
docs/readme-safety-adoption
Open

docs: add a landing README and searchable reference site#89
lan17 wants to merge 22 commits into
mainfrom
docs/readme-safety-adoption

Conversation

@lan17

@lan17 lan17 commented Jul 25, 2026

Copy link
Copy Markdown
Owner

Overview

DialCache's README was serving as its full manual, making it difficult to understand the library before encountering operational detail. The README now explains what the library does and where it fits, followed by a runnable example, the three cache layers, runtime configuration, and links into a structured reference. It keeps the operational tradeoffs visible without slogans or repeated feature pitches.

Thirteen Markdown pages provide a path from getting started and the read model to feature behavior, API lookup, and operations. VitePress renders the same files as a searchable site; contributors maintain one reference that also reads on GitHub.

Documentation structure and contracts

  • Start here: documentation home, getting started, and how DialCache works. The home page also routes common troubleshooting questions to specific sections. Both introductory paths surface the typed serializer prerequisite for non-JSON values, including local caching, and link to the canonical example.
  • Features and behavior: configuration, Redis/Valkey, targeted invalidation, stale-on-error, shadow validation, coalescing, and observability. Guides introduce a feature before describing execution, failures, and compatibility boundaries.
  • Reference and operations: methods, options, defaults, exports, errors, upgrade guidance, and maintenance.

The guides describe the current complete-frame Redis protocol: native SET, primary-routed tracked MGET, observed-watermark conditional refills, application clocks, the one-hour tracked retention cap, retained-snapshot stale recovery, and typed miss reasons. Historical placeholder/stamp behavior appears only in migration guidance.

Configuration is organized around instance resources, operation defaults, and sparse runtime overlays, with option definitions centralized in the API reference. Operational tables explain what policy changes affect: local entries keep their insertion TTL, Redis reads classify age against the invocation's policy, ramp-down bypasses existing entries, and eligible followers can join a leader admitted under earlier policy.

The coalescing guide explains how request and instance scopes compose, what followers inherit, and where deadlines begin and end. Serialization and admitted Redis refills remain on the caller's path and require application-owned settlement budgets. The reference also makes local invalidation boundaries and retained-snapshot recovery races explicit. A remote-only policy does not by itself give every caller a new invalidation check: a follower may join a pre-invalidation flight. The guide provides the full independent-check recipe, including coalesce: false, and a deterministic regression test covers both policies without changing runtime behavior.

The API and feature guides distinguish direct helper contracts from core behavior: manual key ordering and encoding, the bounded JSON type check, native JSON method returns and failures, custom miss normalization, binary frame validation order, safe timestamp checks, strict mutation reply domains, and codec Buffer ownership. Scope closure, zero-capacity local coalescing, falsy results, retry after loader rejection, native compression acceptance, and watermark repair exceptions are explicit. Observability documents fixed Prometheus bucket schemas, structured mismatch logs, and the limits of asynchronous DogStatsD error isolation.

Site and hosting

Stable VitePress 1.6.4 supplies grouped navigation, section outlines, syntax highlighting, browser-local search, and GitHub edit links. docs/.vitepress/config.mts sets /DialCache/ as the project base and participates in the existing strict typecheck.

The Documentation workflow builds every pull request. Pushes to main, or manual runs selected on main, publish through GitHub Pages. Other branches and PRs cannot upload a Pages artifact or deploy. Only the deployment job receives Pages write and OIDC permissions. Actions are pinned, installs use the lockfile, and main deployments are serialized.

Pages is configured to use GitHub Actions with HTTPS enforced, and the github-pages environment permits main. The first publication at https://lan17.github.io/DialCache/ awaits merge. This PR remains unmerged.

README links use the production URL and retain a GitHub Markdown alternative. Reference pages keep relative Markdown links, with shared heading fragments that work in VitePress and GitHub. Generated files are ignored. The npm tarball excludes documentation pages and tooling; its new README arrives with a subsequent package release. The site follows main, and readers are directed to release notes and tagged documentation for installed versions.

corepack pnpm docs:dev
corepack pnpm docs:build
corepack pnpm docs:preview

The maintainer guide documents these commands, page maintenance, and deployment.

Maintenance and runtime scope

The README and getting-started examples run directly as .mts files with node --experimental-strip-types. The existing packed-consumer checks extract the actual first TypeScript blocks from both pages, typecheck them against the installed tarball, execute the documented command, and verify the output. CI also runs these checks at Node.js 22.15.0. No separate copies of the examples or new test dependency are introduced.

Runtime behavior, public APIs, runtime dependencies, and release behavior are unchanged. Runtime source and release configuration edits are comments only.

VitePress is a development dependency. Its scoped Vite override selects patched 6.4.x. Build and development targets use Safari 14.1 for compatibility with the repository's patched esbuild. The existing brace-expansion override advances to 5.0.9. The dependency audit reports zero vulnerabilities.

Validation

  • Local Node.js 22.22.0: corepack pnpm check passed strict typecheck, all 660 unit tests, ESM/CJS builds and declarations, and packed consumers, including the new documentation-example checks.
  • The README revision reran corepack pnpm test:package; all README code examples are unchanged, and the inline-loader link resolves directly to the getting-started example. Production documentation build passed; all 667 rendered local links/assets and README targets resolved, including anchors and the project base path. All 32 TypeScript documentation blocks parsed; the actual direct-key example also passed strict compilation and its documented runtime output check.
  • Browser verification: the new direct-key and fixed histogram-bucket sections render clearly. The revised site renders, the configuration-to-constructor link reaches its heading, and search for independent fence ranks the intended invalidation section first and navigates to it. The earlier changing policy search check also passed. Mobile checks at a 390-pixel viewport verified topic and section navigation, exact-option search, and scrollable API tables without page overflow. The onboarding serializer link reaches its explanation and example. Development-server validation and workflow actionlint also passed during site setup.
  • Source/test coverage audits mapped public execution paths and exports to their reference sections. Focused public-API probes checked key encoding, direct JSON failures, detached scope publication, zero-capacity coalescing, empty results, comparator failure reporting, compression acceptance, and DogStatsD rejection boundaries. git diff --check passed.
  • All checks passed on the final branch: documentation build, package and integration CI, CodeQL, and PR-title validation. CI passed all 660 unit tests and 145 Redis/Valkey integration tests, plus packed consumers, the exact Markdown examples, and zstd at Node.js 22.15.0. The PR run correctly skipped Pages deployment.

Implementation references: VitePress deployment, local search, and GitHub Pages workflow setup.

@lan17
lan17 force-pushed the docs/readme-safety-adoption branch 2 times, most recently from 3d14c88 to 09d3ee5 Compare July 26, 2026 00:27
@lan17
lan17 force-pushed the docs/readme-safety-adoption branch from 09d3ee5 to 4a2dc71 Compare July 26, 2026 03:04
@lan17
lan17 marked this pull request as ready for review August 4, 2026 01:53
@lan17 lan17 changed the title docs: focus README on safe cache rollouts docs: add a landing README and organized reference Sep 6, 2026
@lan17 lan17 changed the title docs: add a landing README and organized reference docs: add a landing README and searchable reference site Sep 6, 2026

@lan17 lan17 left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

README review — prose and accuracy pass

Reviewed the README as it stands at 6c1e0bc, with attention to the latest revision ("make the README more direct and less promotional").

Direction is right. Replacing the 1000-line monolith on main with a lean landing page plus a searchable docs/ site is the change this repo wanted, and it matches the guidance in AGENTS.md. The latest pass also does what its message claims: the promotional register is gone, sentences are shorter and land on concrete subjects, and the new failure-semantics content fills a real gap.

Accuracy checks out. I verified every factual claim the README makes against the source and docs rather than reading it as prose alone. All of them hold:

Claim Verified against
LRU holds 10,000 entries by default src/dialcache.ts:270 (DEFAULT_LOCAL_MAX_SIZE)
getOrLoad() takes a zero-arg loader and a direct key src/dialcache.ts:404
Built-in stale-on-error policy accepts only FallbackTimeoutError src/dialcache.ts:276
A failed cache write does not discard a successful loader result putLocalFailOpen, src/dialcache.ts:1361
Later invalidation does not revoke a retained snapshot docs/stale-on-error.md:11-12, 123-134
Coalescing is scoped to a request or a DialCache instance docs/coalescing.md (Request coalescing)
Node engine range package.json engines
Redis/telemetry clients are optional package.json peerDependenciesMeta

All six deep links resolve to real headings in docs/ (typed-serializer-requirement, getorload, changing-policy-on-a-running-service, keys-ids-and-extra-dimensions, independent-fence-checks, application-owned-budgets).

So everything below is about writing, not correctness.

Worth acting on, roughly in order:

  1. The file-level comment — the README no longer states why you'd want this, while gaining behavior spec. This is the one real decision in the review; the rest are mechanical.
  2. README.md:204 — table header no longer matches its rows.
  3. README.md:77-80getOrLoad() lost its only example.
  4. README.md:183 — one heading over two unrelated subjects.
  5. README.md:190-191 — small drift from docs/concepts.md's list of what needs an application-owned budget.

The remaining five are line-level nits (list ambiguity, a passive sentence, a repeated paragraph opener, a doubled conjunction, one ragged wrap).

Happy to push the mechanical fixes — 2 through 5 plus the nits — as a follow-up commit, leaving 1 as a separate call since it's about what the README is for.


Generated by Claude Code

Comment thread README.md

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The README no longer says why you'd want this.

Splitting the 1000-line monolith into docs/ plus a lean landing page is clearly right. But in trimming the promotional tone, the latest revision also dropped the evaluation content: the "Why DialCache?" framing and the sentence "It fits database lookups, service reads, and reusable computations whose results can be cached." What's left opens with a category label — "a TypeScript caching library for Node.js" — and goes straight to mechanics.

Meanwhile the new "Failures and metrics" section moves in the opposite direction, adding behavior specification to the README.

AGENTS.md:52-53 asks for the reverse on both counts:

Keep the README focused on evaluation and getting started. Document complete feature behavior in docs/ and link it from docs/index.md.

The bulleted pitch doesn't need to come back. One or two direct sentences on what problem this solves and where it fits would restore the evaluation half without reintroducing the sales register.


Generated by Claude Code

Comment thread README.md Outdated
@@ -4,1023 +4,212 @@
[![Codecov](https://codecov.io/gh/lan17/DialCache/branch/main/graph/badge.svg)](https://codecov.io/gh/lan17/DialCache)
[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/lan17/DialCache/badge)](https://scorecard.dev/viewer/?uri=github.com/lan17/DialCache)

Fine-grained TypeScript caching with explicit enabled contexts, request-local memoization, process-local and Redis TTL caching, opt-in stale-on-error recovery, stable key construction, runtime rollout controls, request coalescing, adapter-based observability, and Redis watermark-based targeted invalidation.
DialCache is a TypeScript caching library for Node.js. It wraps a function and
caches its result within a request, in a process-local LRU, or in Redis or Valkey.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The trailing "or … or" muddies the list — a reader parses "in Redis or Valkey" as a fourth item before backtracking.

Suggestion: …within a request, in a process-local LRU, or in a shared Redis or Valkey cache. The added noun makes the last item read as one thing.


Generated by Claude Code

Comment thread README.md Outdated
excluded). Production deployments should use a
[currently supported LTS release](https://nodejs.org/en/about/previous-releases).
Requires Node.js `>=22.15.0 <23.0.0 || >=23.8.0`.
Redis and telemetry clients are installed separately if you use them.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This reads as a passive statement of fact where the previous wording ("optional dependencies you install separately") carried more information in the same space — namely that these are genuinely optional peer deps, which package.json confirms via peerDependenciesMeta.

Suggestion: Install a Redis client and a telemetry client separately if you use those layers.


Generated by Claude Code

Comment thread README.md Outdated
Comment on lines +65 to +68
This prints `Loading from source: 123` twice: once for the first enabled read,
then again for the uncached call. The second enabled read reuses the value.

## Metrics
This example uses only the process-local layer. A TTL with no ramp enables that

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: two consecutive paragraphs open with "This" ("This prints…", "This example uses…"). Varying the second — "The example uses only the process-local layer." — breaks the echo.


Generated by Claude Code

Comment thread README.md Outdated
Comment on lines +77 to +80
For a loader defined at the call site,
[`getOrLoad()`](https://lan17.github.io/DialCache/api.html#getorload) takes a
zero-argument function and a direct key. It uses the same cache behavior without
registering a reusable reader.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getOrLoad() lost its only example here, leaving it described purely abstractly ("takes a zero-argument function and a direct key") in the section whose job is getting started.

The description is accurate — src/dialcache.ts:404 confirms getOrLoad<Value>(load: () => Awaitable<Value>, options) — but the deleted nine-line snippet was the one place a reader saw the inline form actually written out, including how key and defaultConfig differ from the cached() registration above it. I'd keep the snippet and drop the prose instead.


Generated by Claude Code

Comment thread README.md Outdated
Comment on lines +105 to +106
depending on the active layers.
Use `coalesce: false` when callers need independent executions. The

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ragged wrap: line 105 ends a sentence at 31 characters and 106 starts a new one, where every other paragraph in the file flows across the ~80-column wrap. Looks like a leftover from editing — reflowing the paragraph fixes it.

(The claim itself is right: docs/coalescing.md confirms sharing is scoped to the outermost enable() scope or the DialCache instance depending on active layers.)


Generated by Claude Code

Comment thread README.md Outdated
```bash
pnpm benchmark:stale-on-error
```
## Failures and metrics

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Failures and metrics" bundles two unrelated subjects under one heading — error semantics and telemetry have nothing to do with each other beyond both being operational. Splitting into "Failures" and "Metrics" costs one line and makes both scannable.


Generated by Claude Code

Comment thread README.md Outdated
Comment on lines +190 to +191
Redis reads and source fallbacks have separate deadlines. Providers, serializers,
writes, and the underlying clients need application-owned time limits; see

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small accuracy drift from the source doc. docs/concepts.md:120-121 lists what needs application-owned budgets as:

Configuration providers, serializers, Redis writes, and invalidation

This line swapped "invalidation" for "the underlying clients". Invalidation genuinely needs a finite budget, so it's the wrong item to drop — and "the underlying clients" is vague enough that a reader won't know what to bound. Suggest keeping the doc's list.


Generated by Claude Code

Comment thread README.md Outdated

Publishing starts by manually running the `Release` workflow from current `main`. After the package checks pass, Semantic Release selects the next version from Conventional Commits since the highest stable `vX.Y.Z` tag. While the package is pre-1.0, breaking changes bump minor — their `BREAKING CHANGE:` footers still drive full release notes without forcing 1.0.0 — `feat` bumps minor, and every other normal PR-title type (`fix`, `perf`, `docs`, `style`, `refactor`, `test`, `build`, `chore`, `ci`, and `revert`) bumps patch. The highest required bump wins. Major bumps return when 1.0.0 is cut; `release.config.mjs` implements this table and must change together with this section.
Metrics are optional. The [Prometheus and Datadog adapters](https://lan17.github.io/DialCache/observability.html)
report requests, miss reasons, errors, latency, and shadow and recovery outcomes.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The doubled "and" makes the list stumble on the last item.

Suggestion: report requests, miss reasons, errors, latency, and outcomes for shadow validation and stale recovery.

Worth noting the content here is an improvement on the old "feature outcomes" — docs/observability.md:117-121 confirms there really are distinct shadow and stale-recovery counters and age histograms, so the added specificity is earned.


Generated by Claude Code

Comment thread README.md Outdated
Comment on lines +204 to +213
| Topic | Guide |
| --- | --- |
| Add caching to a service | [Getting started](https://lan17.github.io/DialCache/getting-started.html) |
| Understand what runs on a hit, miss, or error | [How DialCache works](https://lan17.github.io/DialCache/concepts.html) |
| Look up methods, options, and exports | [API reference](https://lan17.github.io/DialCache/api.html) |
| Set keys, layers, TTLs, and rollout policy | [Configuration](https://lan17.github.io/DialCache/configuration.html) |
| Connect Redis or Valkey; customize serialization | [Redis and Valkey](https://lan17.github.io/DialCache/redis.html) |
| Understand shared work and deadlines | [Coalescing and liveness](https://lan17.github.io/DialCache/coalescing.html) |
| Build dashboards and diagnose misses | [Observability](https://lan17.github.io/DialCache/observability.html) |
| Upgrade, validate, or contribute | [Upgrading](https://lan17.github.io/DialCache/upgrading.html) · [Maintainer guide](https://lan17.github.io/DialCache/maintainers.html) |

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The header no longer matches its rows. Changing | I want to… | Read | to | Topic | Guide | left all eight rows phrased as reader goals — "Add caching to a service", "Understand what runs on a hit, miss, or error", "Build dashboards and diagnose misses". Those are tasks, not topics.

Either restore the task-oriented header or rewrite the rows as noun phrases. As it stands the mismatch reads like a half-finished edit, and the goal phrasing is arguably the more useful of the two for a landing page.


Generated by Claude Code

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.

1 participant