ZDDC/CLAUDE.md
ZDDC 94591397cf build: pre-release semver for alpha/beta channels
Replace the build-counter version scheme (every alpha push monotonically
bumps the patch number, producing immutable :0.0.X tags that look
indistinguishable from stable releases) with proper semver pre-release
suffixes. Stable owns clean vX.Y.Z; alpha and beta carry
vX.Y.Z-{alpha,beta}[.N] indicating the next-stable target.

The next-stable target is the patch-bump of the latest clean
<prefix>-vX.Y.Z tag. Counter N is per-channel (alpha and beta count
separately) and resets when a new stable advances next-patch. Used
only for zddc-server image tags, where every release is git-tagged;
HTML tools omit the counter since alpha/beta cuts there don't tag.

release-image.sh:
- New CLI: sh release-image.sh [alpha|beta|stable] [<version>].
- Default channel alpha. Version arg only valid (and only optional)
  for stable.
- Auto-derives the version via next_prerelease for alpha/beta, and
  patch-bump for unspecified stable.
- Now creates the git tag itself (the auto-derived version is no
  longer something the operator can predict in advance), but does
  not push — operator finishes with `git push --tags`.

shared/build-lib.sh:
- Add next_prerelease(channel, tag_prefix) helper.
- compute_build_label embeds v<next-stable>-{alpha,beta} in the
  on-page label for plain and --release alpha|beta builds.
- Plain builds: v<next-stable>-alpha · <ts> · <sha>[-dirty]
  --release alpha: v<next-stable>-alpha · <date> · <sha>
  --release beta:  v<next-stable>-beta · <date> · <sha>
  --release [<version>]: v<X.Y.Z> (clean stable, unchanged shape).

Pre-release semver ordering (vX.Y.Z-alpha.1 < vX.Y.Z-alpha.2 <
vX.Y.Z-beta.1 < vX.Y.Z) is honored by registry tag sorting,
git tag --sort=-v:refname, sort -V, npm, cargo — so consumers can
pin or compare versions without surprises.

Existing zddc-server-v0.0.{3..7} git tags and registry tags are
audit history; not rewritten. Going forward, alpha/beta cuts produce
v0.0.8-{alpha,beta}.N format, and clean v0.0.8 is reserved for a
deliberate stable promotion.

freshen-channel needs no code change. It runs --release <channel>
inside a worktree at the latest stable tag, where the build-lib.sh
at that tag is still the old version producing old-format labels;
the first stable cut after this commit will propagate the new format
to subsequent freshens (per the existing "build pipeline at the tag"
reproducibility policy).

AGENTS.md and CLAUDE.md updated.
2026-04-29 17:32:35 -05:00

6.2 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Authoritative docs — read these first

This repo already has two thorough agent-facing references. Always consult them before working — they cover details intentionally omitted here:

  • AGENTS.md — commands, build-system rules, per-tool parser quirks, testing gotchas, git/worktree workflow, release process, zddc-server notes
  • ARCHITECTURE.md — single-file HTML pattern rationale, JS module/state patterns, per-tool architecture, security model

If something in this CLAUDE.md conflicts with those, those win — and please update them rather than letting drift accumulate.

Repo shape

This is a monorepo of independent tools, not one application:

  • archive/, transmittal/, classifier/, mdedit/, landing/ — five self-contained HTML tools, each compiled to a single inlined HTML file in its own dist/. Naming: the first four output dist/tool.html; landing/ outputs dist/index.html (it's the project picker served at the root of zddc-server).
  • zddc/ — Go HTTP server (separate sub-project, podman/podman-compose; Go 1.24+). Serves ZDDC_ROOT/index.html at GET / as the landing page; Accept: application/json on / returns the ACL-filtered project list.
  • shared/base.css plus shared JS modules (zddc.js, hash.js, zddc-filter.js, theme.js, help.js) included by every tool's build, and build-lib.sh (POSIX sh helpers sourced by every tool's build.sh)
  • website/ — published artifacts: index.html (root URL), releases/<tool>_v<X.Y.Z>.html (immutable stable archives), releases/<tool>_stable.html (symlink to current stable), releases/<tool>_{alpha,beta}.html (mutable channel files), and bootstrap/{level1,track-stable,track-beta,track-alpha}/<tool>.html (per-channel level-2 stubs + same-origin level-1 stubs that the home-page install snippets curl into the operator's deployment dir). --release is the only path to publishing releases/; bootstrap/ is regenerated by every plain sh build.sh. There is no website/dev/.
  • tests/ — Playwright specs (Chromium only, requires File System Access API). tests/schema.spec.js validates transmittal.schema.json against canonical fixtures via ajv (only dev dep besides Playwright)

Most-used commands

sh build.sh                                 # build all five HTML tools (dist/ only)
sh tool/build.sh                            # build one (archive|transmittal|classifier|mdedit|landing)
sh tool/build.sh --release [version]        # cut stable; tag, write website/releases/<tool>_v<ver>.html, refresh _stable symlink
sh tool/build.sh --release alpha|beta       # cut channel build; overwrites website/releases/<tool>_<channel>.html (mutable, no tag)
./freshen-channel <tool> <channel>          # rebuild alpha/beta from current stable tag (run after every stable release)
npm test                                    # all Playwright specs (build first!)
npx playwright test <tool>                  # one spec
./dev-server start  # ./dev-server stop     # cache-busting HTTP on :8000

# zddc/ Go server (separate sub-project, not part of sh build.sh)
(cd zddc && go test ./...)                  # unit tests (Go 1.24+)
podman build -t zddc-server zddc/           # build container image
sh release-image.sh [alpha|beta|stable] [<version>] # canonical image release; alpha/beta auto-derive version (default: alpha)

No lint/typecheck/format commands exist for the HTML tools — vanilla JS + POSIX sh by design.

Things that bite if you forget

  • dist/ is gitignored but force-committed (git add -f tool/dist/tool.html). Never hand-edit a dist/ file.
  • Never write to website/index.html, website/releases/<tool>_v*.html, website/releases/<tool>_stable.html, or website/releases/<tool>_beta.html directly — promote via sh tool/build.sh --release [version|alpha|beta]. Stable releases write website/releases/<tool>_v<ver>.html (immutable) and refresh <tool>_stable.html; alpha/beta overwrite <tool>_<channel>.html in place.
  • Pre-release semver for alpha/beta. On-page label embeds vX.Y.Z-{alpha,beta} where X.Y.Z is the next-stable target (patch+1 from latest clean <tool>-vX.Y.Z tag). zddc-server image tags additionally carry a .N counter (v0.0.8-alpha.1, .2, …) since every release is tagged; HTML tools omit the counter (alpha/beta cuts aren't tagged). Stable tags are clean vX.Y.Z.
  • Alpha exception — every plain build dirties website/releases/<tool>_alpha.html. Every tool/build.sh (no flags) mirrors the just-built dist file into <tool>_alpha.html as a real copy (not symlink — the canonical Caddy serves only website/ and can't follow ../ paths). Side-effect: dev builds dirty those files; commit alongside the source change or git checkout to discard.
  • Always build before running tests — Playwright opens dist/tool.html via file://.
  • </ in JS string/template literals breaks inline <script> embedding. shared/build-lib.sh provides escape_js_close_tags; every tool's build.sh runs JS through it before inlining.
  • All ZDDC parsing/formatting/hashing goes through window.zddc (from shared/zddc.js + shared/hash.js + shared/zddc-filter.js). API: parseFilename, parseFolder, parseRevision, formatFilename, formatFolder, compareRevisions, isValidStatus, splitExtension, joinExtension, crypto.{sha256Hex, sha256String, sha256File, bytesToHex}, filter.{parse, matches}. File objects across tools use trackingNumber (string) and extension (string, no leading dot — use zddc.joinExtension(name, ext) to build a filename). Add edge cases to tests/zddc.spec.js, not per-tool tests.
  • Two globals only: window.app (per-tool app state + modules) and window.zddc (shared library). No others — anything that crosses tool boundaries goes through one of these.
  • Worktrees live at ~/src/zddc-<branch>. Check git worktree list before starting a feature branch; never git checkout/switch inside a worktree another agent might be using.
  • Build scripts are POSIX sh with set -eu, not bash. concat_files takes positional args only.