From d122804bdb2e0dc6e4a99d473ed1ed8bde258fb6 Mon Sep 17 00:00:00 2001 From: ZDDC Date: Mon, 27 Apr 2026 13:43:42 -0500 Subject: [PATCH] feat: freshen-channel helper and channel-discipline protocol MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add ./freshen-channel at the repo root for the "drag alpha/beta forward to current stable" workflow. The script uses a temporary git worktree at the latest -v* tag so the main worktree's HEAD is never touched — no checkout, no stash, no race against in-progress dev. Build runs inside the worktree, the resulting _.html is copied back into the main repo's website/releases/, worktree is removed. The on-page label of a freshened build is ` · · ` — the SHA pins which stable was the source, so anyone debugging can `git checkout ` to reproduce. Smoke-tested: ./freshen-channel archive alpha → archive_alpha.html with "alpha · 2026-04-27 · ea385b5" ./freshen-channel transmittal beta → transmittal_beta.html with "beta · 2026-04-27 · ea385b5" ./freshen-channel foobar alpha → usage error ./freshen-channel archive stable → usage error AGENTS.md gains a "Channel discipline (MUST rules)" subsection codifying the protocol the build system can't enforce: 1. Stable doesn't regress — files are immutable; bump for fixes. 2. No backports — bump and let users update pins. 3. Alpha/beta are mutable — never pin in production. 4. Stale-channel rule — after every stable release, freshen alpha and beta so neither is older than current stable. NOT optional. 5. Hotfix path — direct stable cut allowed, no beta soak required; freshen alpha + beta after. 6. Beta soak (recommended) — a few days exposure before promoting. Plus a "Freshen helper" subsection documenting the script. Co-Authored-By: Claude Opus 4.7 (1M context) --- AGENTS.md | 36 +- freshen-channel | 98 + website/releases/archive_alpha.html | 7800 ++++++++++++++++ website/releases/transmittal_beta.html | 10998 +++++++++++++++++++++++ 4 files changed, 18930 insertions(+), 2 deletions(-) create mode 100755 freshen-channel create mode 100644 website/releases/archive_alpha.html create mode 100644 website/releases/transmittal_beta.html diff --git a/AGENTS.md b/AGENTS.md index 6a5df51..26e8117 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -167,16 +167,48 @@ Three channels: - **Beta**: mutable. `sh tool/build.sh --release beta` overwrites `website/releases/_beta.html` in place. No tag. The on-page label is `beta · · ` so the source is recoverable from git via the SHA. - **Alpha**: mutable, analogous. `sh tool/build.sh --release alpha`. -Stable releases do **not** automatically clobber `_alpha.html` / `_beta.html` — those keep whatever was last built into them. To freshen alpha to current stable, `git checkout v.. && sh tool/build.sh --release alpha`. +Stable releases do **not** automatically clobber `_alpha.html` / `_beta.html` — those keep whatever was last built into them. Use `./freshen-channel ` (see "Freshen helper" below) to drag a channel forward to current stable; never `git checkout` the main worktree by hand for this. After cutting a stable release, run `git push --tags` to publish the tag. The "skip if no source change since last tag" guard for stable releases compares **HEAD** to the latest tag — uncommitted working-tree changes are invisible. If you edit a tool and want a stable release to actually fire, commit the change first; otherwise the build prints `no source changes since -vX.Y.Z — skipping` and exits 0. Alpha and beta channel builds always rebuild (no skip check). -Agents must **never** write to `website/releases/` or `website/index.html` directly — always go through `--release`. +Agents must **never** write to `website/releases/` or `website/index.html` directly — always go through `--release` or `./freshen-channel`. `landing/build.sh --release ` additionally writes `website/index.html` (the root URL of zddc.varasys.io). +### Channel discipline (MUST rules) + +The build system does not enforce these. Treating channels carelessly defeats the point of having three. Be disciplined. + +1. **Stable doesn't regress.** No known-broken features that worked in the previous stable. If you ship `v0.0.5` with a bug, the path forward is `v0.0.6` with a fix — never edit `v0.0.5` in place. Stable files are immutable. +2. **No backports.** Don't try to patch an older stable version. Always cut a new stable at a higher version. Users pinned to the old version stay pinned by their own choice; they can move forward when they want. +3. **Alpha and beta are mutable.** Document this anywhere you invite users to test them. Pinning `?v=alpha` (or `_alpha.html`) in a production deployment is a mistake; it gets rebuilt without notice. +4. **Stale-channel rule.** Users tracking alpha (or beta) MUST never see a build older than current stable. After every stable release, run `./freshen-channel alpha` and `./freshen-channel beta` so each channel is at-least-current. This is not optional. +5. **Hotfix path.** For critical bugs: fix on `main`, cut a new stable (no beta soak required), then freshen alpha + beta. Tag the commit message `fix:` or include "hotfix" so the intent is visible in `git log`. +6. **Beta soak before promoting (recommended).** Give a beta a few days of exposure before cutting the same code as stable. Not enforced; use judgment for trivial changes. + +### Freshen helper + +`./freshen-channel ` rebuilds the alpha or beta channel of a tool from its current stable tag. Use it after every stable release (rule 4 above) and any other time alpha/beta has fallen behind stable. + +```sh +./freshen-channel archive alpha +./freshen-channel transmittal beta +``` + +What it does: + +1. Finds the latest `-v*` tag. +2. Creates a temporary git worktree at that tag — does **not** touch the main worktree's HEAD or working tree. +3. Runs `/build.sh --release ` inside the worktree. +4. Copies the resulting `_.html` into the main repo's `website/releases/`. +5. Removes the worktree. + +The on-page label of the freshened build is ` · · ` — the SHA pins which stable was used as the source, recoverable via `git checkout`. + +Note: the build pipeline used is the one **at the tag**, not on `main`. That is intentional (pure reproducibility). If you have made build-system improvements since stable was cut and want the freshen to use them, cut a new stable first. + ### Bootstrap zips `build.sh` regenerates three downloadable zips into `website/` on every invocation: diff --git a/freshen-channel b/freshen-channel new file mode 100755 index 0000000..bdfe39a --- /dev/null +++ b/freshen-channel @@ -0,0 +1,98 @@ +#!/bin/sh +# ============================================================================= +# freshen-channel — rebuild a tool's alpha or beta channel from its current +# stable tag, so users tracking that channel are never on code older than +# current stable. +# +# Usage: +# ./freshen-channel +# tool archive | transmittal | classifier | mdedit | landing +# channel alpha | beta +# +# Why this exists: +# Stable releases do NOT automatically clobber alpha/beta files (see +# AGENTS.md "Channel discipline" rule 4). After cutting stable v0.0.5, +# users pinned to alpha may be on an older build than current stable — +# that violates the stale-channel rule. Run this to drag alpha (or +# beta) forward to whatever stable currently is. +# +# What it does: +# 1. Finds the latest -v* tag. +# 2. Creates a temporary git worktree at that tag — does NOT touch +# your current branch or working tree. +# 3. Runs /build.sh --release inside the worktree. +# 4. Copies the resulting _.html into the main repo's +# website/releases/. +# 5. Removes the worktree. +# +# The on-page label of the freshened build will be +# ` · · ` — the SHA encodes which +# stable was used as the source, so anyone debugging can `git checkout` +# that exact commit. +# +# Note: the build pipeline used is the one AT THE TAG, not the latest +# main. That is intentional — pure reproducibility. If you have made +# build-system improvements since stable was cut and want the freshen +# to use them, cut a new stable that includes those changes first. +# ============================================================================= +set -eu + +TOOL="${1:-}" +CHANNEL="${2:-}" + +case "$TOOL" in + archive | transmittal | classifier | mdedit | landing) ;; + *) + echo "usage: $0 " >&2 + echo " tool: archive | transmittal | classifier | mdedit | landing" >&2 + exit 1 + ;; +esac + +case "$CHANNEL" in + alpha | beta) ;; + *) + echo "usage: $0 " >&2 + echo " channel: alpha | beta (stable is what you are freshening FROM)" >&2 + exit 1 + ;; +esac + +REPO=$(cd "$(dirname "$0")" && pwd) + +# Find the latest stable tag for the tool. +LATEST_TAG=$(git -C "$REPO" tag --list "${TOOL}-v*" --sort=-v:refname | head -1) +if [ -z "$LATEST_TAG" ]; then + echo "error: no stable tag found for ${TOOL} (looking for ${TOOL}-v*)" >&2 + echo " cut a stable release first: sh ${TOOL}/build.sh --release [version]" >&2 + exit 1 +fi + +# Temporary detached worktree at the stable tag. Cleaned up on exit. +WT=$(mktemp -d) +cleanup() { + git -C "$REPO" worktree remove --force "$WT" >/dev/null 2>&1 || true + rm -rf "$WT" +} +trap cleanup EXIT INT TERM + +echo "Freshening ${TOOL} ${CHANNEL} from ${LATEST_TAG}" +git -C "$REPO" worktree add --quiet --detach "$WT" "$LATEST_TAG" + +# Build in the worktree. The tool's build.sh writes the channel artifact +# to "$WT/website/releases/_.html"; we then copy it into +# the main worktree. +sh "$WT/${TOOL}/build.sh" --release "$CHANNEL" + +SRC="$WT/website/releases/${TOOL}_${CHANNEL}.html" +DST="$REPO/website/releases/${TOOL}_${CHANNEL}.html" +if [ ! -f "$SRC" ]; then + echo "error: build did not produce $SRC" >&2 + exit 1 +fi + +mkdir -p "$REPO/website/releases" +cp "$SRC" "$DST" +echo "Wrote $DST" +echo "Done. ${CHANNEL} channel for ${TOOL} now reflects ${LATEST_TAG}." +echo "Commit the change: git add $DST && git commit" diff --git a/website/releases/archive_alpha.html b/website/releases/archive_alpha.html new file mode 100644 index 0000000..f701b9f --- /dev/null +++ b/website/releases/archive_alpha.html @@ -0,0 +1,7800 @@ + + + + + + ZDDC Archive + + + +
+ + + + +
+
+
+ ZDDC Archive + alpha · 2026-04-27 · ea385b5 +
+ + +
+
+ + +
+
+ + +
+ + + + +
+ +
+ + + + + + + +
+ + +
+ +
+ +
+ + + +
+
+ + +
+ + + + + + + + + + + +
+
+ Tracking Number + +
+ +
+
+
+ Title + +
+ +
+
+
+ + Revisions +
+ +
+
+
+ + +
+ 0 files + 0 selected + +
+
+
+ + + + + +
+
+

Welcome to ZDDC Archive

+

Click Add Local Directory to select an archive folder to browse.

+

This browser provides a convenient interface for searching and retrieving files from ZDDC-compliant archives.

+

How to navigate:

+
    +
  • Select a party to see their transmittal folders; toggle folder types (Issued, Received, MDL, Incoming) above the list
  • +
  • Select transmittal folders to see their files
  • +
  • Use Ctrl+Click to select multiple folders
  • +
  • Use Shift+Click to select a range
  • +
  • Ctrl+Click chevrons to recursively expand/collapse
  • +
+ +
+ ⚠️ Windows Path Length Deficiency +
+

Microsoft Windows has a legacy 260-character path limit that affects most applications. If you see "files skipped" warnings, use Microsoft's own workaround:

+
    +
  1. Open Command Prompt as Administrator
  2. +
  3. Map your archive to a short drive letter:
    + subst Z: "C:\Your\Long\Path\To\Archive" +
  4. +
  5. Use the Z: drive in Archive Browser
  6. +
  7. To remove later: subst Z: /d
  8. +
+

This limitation dates back to Windows 95. The mapping persists until reboot.

+
+
+ +

Note: This application works entirely in your browser and does not transmit any data.

+
+
+ + + + + +
+ + + + diff --git a/website/releases/transmittal_beta.html b/website/releases/transmittal_beta.html new file mode 100644 index 0000000..085ed6e --- /dev/null +++ b/website/releases/transmittal_beta.html @@ -0,0 +1,10998 @@ + + + + + + + + + ZDDC Transmittal + + + +
+ + JavaScript not available +
+ ZDDC Transmittal + beta · 2026-04-27 · ea385b5 +
+
+
+ + +
+
+
+
+ + + + +
+ + +
+

+ Integrity + Not Validated (requires JavaScript) +

+
+
+
+ +
+
+ + +
+
Drop folder to scan / verify Drop HTML or JSON to import
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
# + + + + + + + + + + + + + +
+
+
+ +
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +