git:20260927.1b4c960 to git:20260929.4b792eb

45 added, 19 removed. Audit A to A.

---
name: worca-changelog
- description: Build a "What's new in Worca" changelog page for @worca/app — a scroll-revealed, screenshot-led ship log in the established Worca design (hero ribbon, kicker/headline/chips per feature, live demo cards, receipts) — from the merged PRs since a reference version, then publish it as an Artifact. Triggers on "changelog", "what's new", "ship log", "release notes", "worca-changelog", or any request to write up what shipped since a version.
+ description: Build a "What's new in Worca" changelog page for @worca/app — a scroll-revealed, screenshot-led ship log in the established Worca design (hero ribbon, kicker/headline/chips per feature, live demo cards, receipts) — from the merged PRs since a reference version, preview it as an Artifact, and record it for docs.worca.dev/changelog. Triggers on "changelog", "what's new", "ship log", "release notes", "worca-changelog", or any request to write up what shipped since a version.
---
# Worca changelog entry
- A changelog entry is a **self-contained HTML page** in the ship-log design,
- built from the PRs merged since a reference version, and published as an
+ A changelog entry is an **HTML page** in the ship-log design, built from the
+ PRs merged since a reference version. It is served for good at
+ `https://docs.worca.dev/changelog/<VERSION>/` and previewed first as a private
Artifact. It is not a bullet list of commits: every section sells one
user-facing capability with a headline, a screenshot, and a small live demo
of the mechanism.
The output is written into `docs/changelog/` **on the current branch, left
uncommitted**. This skill never branches, commits, pushes, or opens a PR —
see Step 7.
The design, layout and writing rules live next to this file — read both
before writing a line of copy or markup:
- `DESIGN.md` — tokens, components, section anatomy, demo recipes, voice.
- `template.html` — the page skeleton with every component wired up. Copy
it; never restyle it.
- `inline-assets.mjs` — turns local `<img src>` paths into data URIs so the
page publishes as one file.
**Usage:**
- `/worca-changelog` — offer the last stable release as the delta start
- `/worca-changelog --from:1.1.1` — delta since that version (tag or bare version)
- `/worca-changelog --from:1.1.1 --to:worca-app-v1.2.0-rc.3` — explicit end ref (default `HEAD`)
- - `/worca-changelog --no-publish` — build the file, skip the Artifact
+ - `/worca-changelog --no-publish` — build the file, skip the Artifact preview
---
## Step 1: Resolve the range
The delta runs from a **reference version** to an **end ref**. A stable
release is the natural reference: it is the last thing a `latest` user has,
so "what's new since it" is exactly the RC's story.
```bash
# Last stable release: highest worca-app-v tag with no pre-release suffix.
git fetch --quiet --tags origin
STABLE=$(git tag --sort=-v:refname | grep -E '^worca-app-v[0-9]+\.[0-9]+\.[0-9]+$' | head -1)
LAST_RC=$(git tag --sort=-v:refname | grep -E '^worca-app-v[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+$' | head -1)
echo "stable: $STABLE npm latest: $(npm view @worca/app version) last rc: $LAST_RC"
node -p "require('./package.json').version" # the version this entry describes
```
If `--from:` was **not given**, do not pick silently: **offer the last stable
release** with `AskUserQuestion`. Put it first and mark it recommended; the
other options are the last RC and "other" (free text). If the stable tag and
`npm view @worca/app version` disagree, say so in the question — one of them
is stale.
A bare version (`1.1.1`) means the tag `worca-app-v1.1.1`. Verify the tag
exists (`git rev-parse -q --verify refs/tags/<tag>`) before using it; stop on
a miss rather than guessing at a nearby tag.
The end ref defaults to `HEAD`. The entry's **version label** is
`package.json`'s version at the end ref (`git show <to>:package.json`).
Print the resolved range and continue:
```
Changelog range: worca-app-v1.1.1 → HEAD (1.2.0-rc.3)
```
---
## Step 2: Collect the delta
Both views, always — PRs give the story, the first-parent log catches what
landed without a PR.
```bash
FROM=worca-app-v1.1.1; TO=HEAD
SINCE=$(git log -1 --format=%cI "$FROM")
gh pr list --state merged --base dev --search "merged:>=${SINCE%%T*}" --limit 200 \
--json number,title,body,mergedAt,url,labels \
--jq "[.[] | select(.mergedAt > \"$SINCE\")] | sort_by(.mergedAt) | .[] | \"#\(.number)\t\(.mergedAt[:10])\t\(.title)\""
git log "$FROM".."$TO" --first-parent --format='%h %s'
```
Read every PR body (`gh pr view <n> --json body --jq .body`). The body is
where the user-facing framing lives; the title is often internal.
Then **cluster into 4–7 themes**. A theme is something a user can point at
in the product: a new view, a new command, a behaviour that changed. Fold
these in rather than giving them a section:
- `chore(release)` bumps, CI, test-only and Windows-path fixes → the
receipts section, as numbers.
- Refactors and internal plumbing → mention in the sub of the feature they
enable, or drop.
- Bug fixes → one "Fixes" theme only if there are several visible ones;
otherwise a chip on the relevant feature (`<span class="chip">no more X</span>`).
Order themes by how much a user will care, biggest first. The hero's chips
and ribbon list them in that order.
---
## Step 3: Collect the receipts
The closing section carries six numbers. Compute them; never estimate.
```bash
git diff --shortstat "$FROM".."$TO" # files, +lines, -lines
git rev-list --count --first-parent "$FROM".."$TO" # commits on dev
gh pr list --state merged --base dev --search "merged:>=${SINCE%%T*}" --json mergedAt \
--jq "[.[] | select(.mergedAt > \"$SINCE\")] | length" # PRs merged
git diff --stat "$FROM".."$TO" -- '*.test.mjs' 'test/' | tail -1 # test lines
npm test 2>&1 | grep -E '^# (tests|pass|fail) ' # suite size, must be 0 fail
```
Pick the six that tell the story (tests green, lines landed, PRs merged,
schema versions bumped, a security property, a round-trip proven). Two of
the six may be a cropped screenshot instead of a number — see `DESIGN.md`.
---
## Step 4: Capture screenshots
Every feature section wants a real screenshot; a section with no UI surface
(a CLI change, a policy) gets two demo cards instead, as `template.html`
shows for `s3`.
Follow the sandbox recipe in `docs/screenshots.md` — `HOME` and `WORCA_HOME`
both set to a throwaway dir, seeded mock runs, demo projects with plausible
names — so nothing private lands in a published page. Run the mock server
from the current checkout; the sandbox is runtime state only and produces
no branch, worktree, or commit of its own. Then, with the UI running (the
`run` skill knows how), capture at **1440 × 900**, light theme, and save as
PNG under:
```
docs/changelog/shots/<VERSION>/<section-id>.png e.g. shots/1.2.0-rc.3/s1.png
```
Crop in markup, not in the file: the `.shot .crop` container takes
`max-height`, and the `<img>` takes `width:130%;max-width:none;margin:…` to
zoom on the part that matters. Keep the original so a later re-crop is free.
Compress before inlining — screenshots dominate the page weight:
```bash
sips -s format jpeg -s formatOptions 82 s1.png --out s1.jpg # macOS; ~5× smaller
```
---
## Step 5: Write the copy, then the page
Read `DESIGN.md` → *Voice* before writing. The shape of every section is
fixed; only the words and the demo change:
| Slot | Rule |
| --- | --- |
| kicker | 1–2 words naming the area: `Budget`, `Routing`, `Team`. Dot colour from the palette table. |
| h2 | ≤ 7 words, a full sentence with a period. Obvious before clever: a reader must know what the feature is from the headline alone (*New to Worca? Follow the checklist.*), never a riddle that needs the sub to decode. |
| sub | **Problem first, in bold, then the answer.** Line 1 is one plain question or pain the reader recognises, wrapped in `<b>…</b>` and followed by `<br>`. Line 2 starts with *Now …* and says what Worca does and how, in words a first-time user understands. ≤ 52ch measure, no "we". |
| chips | 2–4 plain phrases a user understands at a glance, and only ones that matter (`highlights the real button`, `stored in your git remote`). Numbers go in `<b>`. No tool names, flags, schema versions, internal terms, or shorthand a reader would have to decode. |
| demo | A 10–20 line CSS/JS loop that shows the *mechanism* — precedence, masking, a flag appearing. Reuse a recipe from `DESIGN.md` before inventing one. Its label, steps and note follow the same plain-words rule as the chips. |
| shot | The screenshot in a `.shot` frame with a one-line `.shot-cap` that says what the reader is looking at. |
Build the page:
1. Copy `template.html` to `docs/changelog/worca-app-v<VERSION>.src.html`.
2. Fill every `{{…}}` slot; delete the sections you don't need, duplicate
the ones you do. Keep ids sequential (`s0` hero … `sN` receipts) — the
dot rail is built from them.
3. Set the hero ribbon text to the section names, uppercased, `·`-separated,
**repeated twice** so the drift never shows the end.
4. Point every `<img src>` at the local file (logo: `ui/public/assets/worca-logo.png`).
5. Inline and check weight:
```bash
node .claude/skills/worca-changelog/inline-assets.mjs \
docs/changelog/worca-app-v<VERSION>.src.html \
docs/changelog/worca-app-v<VERSION>.html
```
The script fails above 15 MB (the Artifact ceiling is 16 MB) and warns
above 4 MB — the sibling ship logs weigh ~1.6 MB. Over 4 MB means a
screenshot went in as PNG; go back to Step 4.
6. Open the built file in a browser and check, in this order: reveals fire
as you scroll; every demo loops; the rail dot follows the section; no
horizontal scroll at 390 px wide; `prefers-reduced-motion` shows every
demo in its final state. Fix in the `.src.html`, rebuild.
- The `.src.html` is the editable source and travels with the built file —
- the built one is what gets published, the source is what gets edited next
- time. Both are written into the working tree of the current branch (Step 7).
+ 7. After Step 6 has added the entry to `entries.json`, check that the docs
+ site builds with it:
+ ```bash
+ node docs-site/build.mjs # fails on a missing image, a page without an entry, or the reverse
+ ```
+
+ The `.src.html` and `shots/<VERSION>/` are the entry: they are what gets
+ committed, and what docs.worca.dev serves (`docs-site/build.mjs` gives the
+ page a document shell and serves the screenshots as files). The built
+ `worca-app-v<VERSION>.html`, with the screenshots embedded, exists only to
+ publish the Artifact preview. It is git-ignored and never committed.
+
---
- ## Step 6: Publish
+ ## Step 6: Publish the preview and record the entry
+ The Artifact is a **private preview**, for reviewing the page before it goes
+ out. The public, permanent address is the docs site (Step 7).
+
Unless `--no-publish`:
1. Load the `artifact-design` skill (the Artifact tool requires it before
any publish; the page's design is already settled, so the pass is
confirmation, not redesign).
2. Publish `docs/changelog/worca-app-v<VERSION>.html` with:
- title: `Worca — What's new in <VERSION>` (the `<title>` tag already says this)
- favicon: `🚢` on first publish, omitted on redeploys
- description: one sentence — the hero sub is usually right.
- 3. Record it in the index, `docs/changelog/README.md` — one row per entry:
- version, range, date, artifact URL. Create the file from the header in
- `DESIGN.md` → *Index* if it does not exist.
+ Always, with or without `--no-publish`, record the entry in
+ `docs/changelog/entries.json`, newest first (see `DESIGN.md` → *Index*):
+
+ ```json
+ { "version": "1.7.0", "since": "1.6.0", "date": "2026-10-02", "artifact": "https://claude.ai/artifact/…" }
+ ```
+
+ Leave `artifact` out when nothing was published. The docs site's release list
+ reads its summary and headlines from the page itself, so nothing else goes
+ into the record.
+
Redeploys of the same version go to the same URL: edit the source, rebuild,
- publish the same path again. A new version is a new file and a new URL.
+ publish the same path again. A new version is a new file, a new URL and a new
+ record.
---
## Step 7: Leave it on the current branch
The entry stays **in the working tree of the branch that is checked out**.
Do not create a branch, a worktree, a commit, a push, or a PR for it — a
changelog is release material, and the release engineer decides when and
how it lands (folded into the release commit, its own PR, or not at all).
+ It goes live on docs.worca.dev only once it is on `dev` **and** someone runs
+ `npm run docs:publish`, which moves the `docs-live` pointer.
One PR per changelog is exactly the churn this rule avoids.
Show what is waiting, then stop:
```bash
git status --short docs/changelog/
```
Finish with the summary:
```
Changelog entry ready
Range: worca-app-v1.1.1 → HEAD (1.2.0-rc.3)
Sections: 6 features + receipts
- Page: docs/changelog/worca-app-v1.2.0-rc.3.html (1.4 MB)
- Artifact: <url> | not published (--no-publish)
- Files: uncommitted on <branch> — 9 files under docs/changelog/
+ Page: docs/changelog/worca-app-v1.2.0-rc.3.src.html (+ 6 screenshots)
+ Preview: <artifact url> | not published (--no-publish)
+ Docs: https://docs.worca.dev/changelog/1.2.0-rc.3/ (live after commit + push to dev + npm run docs:publish)
+ Files: uncommitted on <branch> — 8 files under docs/changelog/
```
Then, always, print a **release announcement** in one fenced block the user
can copy straight into a team chat:
````
```
Worca <VERSION> released
Changes:
1. <one sentence per section, in the page's order>
2. …
npm install -g @worca/app@<VERSION>
- <artifact url>
+ https://docs.worca.dev/changelog/<VERSION>/
```
````
- One numbered item per feature section (not the receipts), in page order.
Fold the small changes that only got a chip into the closest item or one
last "also" item, never a list of their own.
- Each item is one sentence (two at most) that says what a teammate can do now
and why it matters, in the same plain words as the page: *Your team can
share one hosted Worca while each person's runs are charged to their own
key or Claude subscription. Keys are kept in a separate key service, so
neither Worca nor its agents can read them, which is a strong protection
against prompt injection.* No PR numbers, internal names or flags. A
command the reader types, such as `worca runs`, stays in backticks.
- The install line pins the exact version, even for an RC:
`npm install -g @worca/app@1.2.0-rc.3`.
- - With `--no-publish`, leave out the link line and say below the block that
- the page is not published. When it is published, note below the block that
- the Artifact is private until it is shared from the page's Share menu.
+ - The link is the docs page, not the Artifact: the docs page is public and
+ permanent, while the Artifact is private until it is shared. Below the block,
+ say that the link works once the entry is on `dev` and `npm run docs:publish`
+ has run, and give the Artifact URL as the preview to review before then.