Skip to content

docs cache: close the publication window with a stable indirection #14

Description

@amondnet

Follow-up from a declined review finding on #13 (thread).

What

publish() in scripts/docs.ts swaps a documentation tree into place with two renames: the existing tree moves aside, the new one moves in. Between them the canonical cache path does not exist.

Why it was left

The window is metadata-only and the cost is bounded. A reader that loses the race falls through to a re-download, because resolveDocs treats a missing or incomplete tree as something to repair. The only path that turns into an unavailable result is --no-fetch during a concurrent refresh.

The two remedies suggested in review both cost more than that:

  • A per-tag lock adds stale-lock recovery to a cache whose whole failure story today is "re-download", and a crashed holder blocks every reader until a timeout nobody can tune correctly.
  • A stable indirection — a symlink pointing at a content-addressed directory — removes the window properly, but it changes the on-disk layout that path and index hand to callers.

What to do here

Build the indirection, if --no-fetch robustness under concurrent refresh turns out to matter:

  • Unpack to docs/<tag>.<digest>/, then renameSync a symlink at docs/<tag> onto it — a symlink swap is atomic, so no reader ever observes a missing path.
  • Decide what path and index report: the symlink keeps callers stable, the resolved target makes Grep output legible. Pick one and document it.
  • Reclaim superseded content directories the way sweepLeftovers reclaims staging and displaced ones.
  • Check Windows, where symlink creation needs either Developer Mode or elevation. A junction or a small pointer file may be the portable form.

Not urgent

No user has hit this. Two resolvers have to publish the same tag at the same moment, and the loser re-downloads unless it passed --no-fetch.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions