From 449cece0055bf6c417b07b373323dddcfeafda62 Mon Sep 17 00:00:00 2001 From: Dmitrii Ostasevich Date: Mon, 27 Jul 2026 14:45:11 +0200 Subject: [PATCH 1/2] docs(release): decouple the demo-webchat bump from promotion to latest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The post-release checklist listed the demo-webchat bump as step 5, after the 'promote to latest' step, so it read as gated on promotion — which happens ~1 week later, once attention has moved on. It isn't gated. Pointing demo-webchat at the freshly published pre-release is what gives QA something to exercise during the promotion window; waiting for promotion inverts the dependency. Practice already works this way: the 3.47.0 demo bump (cognigy#13417) landed 2026-07-13, the same day 3.47.0 was published, while promotion ran 2026-07-22. Split §8 into 8a (same-day work, incl. the demo bump), 8b (the bump itself) and 8c (promotion, the only part that waits for QA), and record what the bump actually involves: it's a PR against the protected main of the Cognigy/cognigy monorepo, the pin is exact, package.json must be hand-edited (no trailing newline, tabs) with the lockfile synced via npm install --package-lock-only, and the lockfile churn wants auditing so only @cognigy/webchat changes as a direct dep. Also document two things this release surfaced: publish.yml is named 'Publish to NPM (with pre-release tag)' so --workflow Publish misses it, and chat-components' release.yml fails with 'Bad credentials' on an expired RELEASE_ACTION_TOKEN — the tag push then creates no release and nothing reaches npm, silently. Co-Authored-By: Claude Opus 5 --- .claude/skills/webchat-release/SKILL.md | 70 ++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 7 deletions(-) diff --git a/.claude/skills/webchat-release/SKILL.md b/.claude/skills/webchat-release/SKILL.md index 16ece245..31549cc7 100644 --- a/.claude/skills/webchat-release/SKILL.md +++ b/.claude/skills/webchat-release/SKILL.md @@ -1,6 +1,6 @@ --- name: webchat-release -description: Cut, build, and ship a new @cognigy/webchat release in this repo — version bump, dependency updates (axios, @cognigy/chat-components, @cognigy/socket-client), OSS license regeneration, the release PR, tagging, the Automatic Draft Release workflow, the changelog, and publishing as a pre-release to npm. Use whenever the user wants to release Webchat, cut/prepare a new version, bump the version, "do a webchat release", update a core dependency and ship it, create or fill a draft release, publish a pre-release, or asks about the release/draft/publish CI workflows. Also covers the upstream pre-flight — detecting merged-but-unreleased @cognigy/chat-components work and cutting a chat-components release first so the Webchat release can include it ("include the latest chat-components"). Also use when diagnosing release CI failures (E2E specs broken by a dependency bump, Format/Prettier check, OSS license version mismatch). +description: Cut, build, and ship a new @cognigy/webchat release in this repo — version bump, dependency updates (axios, @cognigy/chat-components, @cognigy/socket-client), OSS license regeneration, the release PR, tagging, the Automatic Draft Release workflow, the changelog, and publishing as a pre-release to npm. Use whenever the user wants to release Webchat, cut/prepare a new version, bump the version, "do a webchat release", update a core dependency and ship it, create or fill a draft release, publish a pre-release, or asks about the release/draft/publish CI workflows. Also covers the upstream pre-flight — detecting merged-but-unreleased @cognigy/chat-components work and cutting a chat-components release first so the Webchat release can include it ("include the latest chat-components") — and the downstream demo-webchat bump in the Cognigy/cognigy monorepo (service-webchat), which happens right after publishing and is not gated on promotion to latest. Also use when diagnosing release CI failures (E2E specs broken by a dependency bump, Format/Prettier check, OSS license version mismatch). --- # Releasing @cognigy/webchat @@ -71,6 +71,15 @@ gh run list --repo Cognigy/chat-components --limit 5 npm view @cognigy/chat-components version # must show 0.NN.0 before step 1 ``` +**Known failure: the tag push creates no release.** `release.yml` authenticates with a hand-managed `RELEASE_ACTION_TOKEN` PAT, and when it expires the run fails with `##[error]Bad credentials` — the tag exists, but no GitHub release is created, so `publish.yml` (on `release: published`) never fires and **nothing reaches npm**. Silent unless you check, because the tag push itself succeeds. Diagnose and unblock: + +```bash +gh run view --repo Cognigy/chat-components --log-failed | grep -iE 'bad credentials|error' +gh release create v0.NN.0 --repo Cognigy/chat-components --title "v0.NN.0" --generate-notes --verify-tag +``` + +That manual create is equivalent to what the workflow does (non-draft, non-prerelease, generated notes) and fires `publish.yml` normally. It unblocks the release but does **not** fix the cause — the secret needs rotating by a repo admin, or every future release fails the same way. Note the trap if someone proposes switching to `GITHUB_TOKEN`: releases created by `GITHUB_TOKEN` don't trigger other workflows, so `publish.yml` would stop firing entirely. + **This blocks the Webchat release.** `npm install` in Webchat can only resolve `0.NN.0` once it's live on npm, so the Webchat half waits on the upstream PR being merged and published — a human-gated step in another repo. Don't try to route around it with a `file:`/tarball dependency; that is not shippable. ### 0c. Two upstream gotchas worth knowing @@ -203,15 +212,61 @@ gh release edit v3.NN.0 --repo Cognigy/Webchat --notes-file notes.md ## 8. Publish as a pre-release, then the post-release checklist -Publishing is the point of no return — `.github/workflows/publish.yml` runs `on: release: published` and does `npm publish --tag pre-release`, so the version lands on npm under the **`pre-release`** dist-tag (never `latest` automatically). **Confirm with the user before publishing.** When publishing, **check "Set as a pre-release"** on the GitHub release. +Publishing is the point of no return — `.github/workflows/publish.yml` (named **"Publish to NPM (with pre-release tag)"**, so `gh run list --workflow Publish` won't match it) runs `on: release: published` and does `npm publish --tag pre-release`, so the version lands on npm under the **`pre-release`** dist-tag (never `latest` automatically). **Confirm with the user before publishing.** When publishing, **check "Set as a pre-release"** on the GitHub release — or `gh release edit v3.NN.0 --draft=false --prerelease`. Afterwards confirm `npm view @cognigy/webchat dist-tags` shows `latest` still on the _previous_ version and `pre-release` on the new one. + +The checklist splits into what happens **now** and what genuinely waits for QA — the two are independent, and conflating them is what strands the demo-webchat bump (§8b). -After publishing (per the Confluence runbook): +### 8a. Immediately after publishing — none of this waits for promotion 1. Verify the new version loads on the **Testing Webchat** page. -2. Tag this release's tickets with `webchat-3.NN`, plus the release tech-story. -3. Create a QA tech-story; await QA approval (~1 week). For a patch, ask QA to prioritize. -4. After the green light, promote to latest by running the **Promote Release to Latest** workflow (`promote-to-latest.yml`) — Actions → Run workflow → input the release tag `v3.NN.0`. It marks the GitHub release `--latest`, runs `npm dist-tag add @cognigy/webchat@3.NN.0 latest`, and removes the `pre-release` dist-tag if it still points there. (Editing the GitHub release in the UI alone does **not** update npm — there's no `release: edited` automation; this workflow is the mechanism.) Then re-verify on the Testing Webchat page and confirm `npm view @cognigy/webchat dist-tags`. -5. Update the demo-webchat version in `service-webchat` (`services/service-webchat/package.json`), `npm i`, commit, push. +2. **Bump demo-webchat** in `Cognigy/cognigy` — see §8b. Do it here, not after promotion. +3. Tag this release's tickets with `webchat-3.NN`, plus the release tech-story. +4. Create a QA tech-story, then await QA approval (~1 week) before §8c. For a patch, ask QA to prioritize. + +Only step 4 involves waiting; steps 1–3 are all same-day work. + +### 8b. Bump demo-webchat — a `Cognigy/cognigy` PR, decoupled from promotion + +The demo webchat served by `service-webchat` lives in the **`Cognigy/cognigy`** monorepo at `services/service-webchat/package.json`, pinned to an **exact** version (no caret). + +**This is not gated on promotion to `latest`.** Pointing the demo at the freshly published **pre-release** version is precisely what gives QA something to exercise during the ~1 week promotion window; waiting for promotion would invert the dependency and defeat the purpose. The exact pin resolves fine regardless of dist-tag, so `pre-release` is not an obstacle. Existing practice confirms it: the 3.47.0 demo bump ([cognigy#13417](https://github.com/Cognigy/cognigy/pull/13417)) landed **2026-07-13**, the same day 3.47.0 was published, while promotion to `latest` ran **2026-07-22** — nine days later. + +Because `Cognigy/cognigy`'s `main` is protected (1 approving review, a required team review, squash-only), this is a PR — not a direct push. From a worktree so you don't disturb whatever branch the monorepo checkout is on: + +```bash +cd ~/repos/cognigy && git fetch origin main +git worktree add /tmp/demo-bump -b chore/demo-webchat-3.NN.0 origin/main +``` + +Edit the pin by hand, then sync **only** the lockfile: + +```bash +cd /tmp/demo-bump/services/service-webchat +npm install --package-lock-only # updates package-lock.json without touching package.json +``` + +- **Edit `package.json` by hand, don't let npm rewrite it.** The file has **no trailing newline** and uses tabs; `npm install @` reformats it and appends a newline, adding diff noise. Hand-editing plus `--package-lock-only` keeps `package.json` to a single changed line. +- **Audit the lockfile churn before committing.** `@cognigy/webchat` must be the _only_ changed **direct** dependency. Everything else should be transitive — `@cognigy/chat-components` via webchat, and the caret-ranged `@radix-ui/*` tree via chat-components' `react-popover`. A changed direct dep that isn't webchat means unrelated drift got pulled in; drop it. Verify rather than eyeball a ~200-line diff: + +```bash +python3 - <<'EOF' +import json, subprocess +old = json.loads(subprocess.run(['git','show','HEAD:services/service-webchat/package-lock.json'], + capture_output=True, text=True).stdout) +new = json.loads(open('services/service-webchat/package-lock.json').read()) +po, pn = old['packages'], new['packages'] +changed = {k for k in set(po) | set(pn) if po.get(k, {}).get('version') != pn.get(k, {}).get('version')} +direct = set(json.loads(open('services/service-webchat/package.json').read()).get('dependencies', {})) +print("direct deps changed:", sorted(k for k in changed if k.replace('node_modules/','') in direct)) +print("total changed:", len(changed)) +EOF +``` + +The monorepo's pre-commit hooks (`pretty-quick`, `lint-staged`) only target `services/service-ui/**`, so they no-op here — but they do run, so don't mistake their output for an error. Open the PR titled `chore(service-webchat): update demo webchat to 3.NN.0`. + +### 8c. After the QA green light — promote to `latest` + +Run the **Promote Release to Latest** workflow (`promote-to-latest.yml`) — Actions → Run workflow → input the release tag `v3.NN.0`. It marks the GitHub release `--latest`, runs `npm dist-tag add @cognigy/webchat@3.NN.0 latest`, and removes the `pre-release` dist-tag if it still points there. (Editing the GitHub release in the UI alone does **not** update npm — there's no `release: edited` automation; this workflow is the mechanism.) Then re-verify on the Testing Webchat page and confirm `npm view @cognigy/webchat dist-tags`. ## Quick reference — gotchas @@ -225,3 +280,4 @@ After publishing (per the Confluence runbook): - Squash merges orphan the `npm version` tag — re-point `v3.NN.0` to the `main` squash commit before pushing it. - Changelog range is between `Release/*` commits on `main`, not between `vX.Y.Z` tags. - Pushing the tag → draft release. Publishing the release → npm `pre-release` dist-tag. The **Promote Release to Latest** workflow (manual dispatch) → npm `latest` (and drops `pre-release`). Editing the release in the UI does not touch npm. +- The demo-webchat bump in `Cognigy/cognigy` is **not** gated on promotion to `latest` — do it right after publishing, so QA can exercise the pre-release during the promotion window (§8b). From baff16c0cd658f4b46575b6fd7e937b57f97850e Mon Sep 17 00:00:00 2001 From: Dmitrii Ostasevich Date: Mon, 27 Jul 2026 15:02:40 +0200 Subject: [PATCH 2/2] docs(release): fix lockfile-audit snippet paths in the demo-webchat section The snippet followed a 'cd services/service-webchat' but then opened 'services/service-webchat/package-lock.json', which resolves to a doubled path from that directory and raises FileNotFoundError. It only worked when run from the repo root, which is not where the surrounding instructions leave you. Make all three paths relative to the service directory, git's 'HEAD:./package-lock.json' included, and state which directory to run it from. Verified by running the snippet verbatim from services/service-webchat: it prints the documented ['node_modules/@cognigy/webchat'] against 23 total changed packages. Co-Authored-By: Claude Opus 5 --- .claude/skills/webchat-release/SKILL.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.claude/skills/webchat-release/SKILL.md b/.claude/skills/webchat-release/SKILL.md index 31549cc7..d4480278 100644 --- a/.claude/skills/webchat-release/SKILL.md +++ b/.claude/skills/webchat-release/SKILL.md @@ -248,20 +248,24 @@ npm install --package-lock-only # updates package-lock.json without touchin - **Edit `package.json` by hand, don't let npm rewrite it.** The file has **no trailing newline** and uses tabs; `npm install @` reformats it and appends a newline, adding diff noise. Hand-editing plus `--package-lock-only` keeps `package.json` to a single changed line. - **Audit the lockfile churn before committing.** `@cognigy/webchat` must be the _only_ changed **direct** dependency. Everything else should be transitive — `@cognigy/chat-components` via webchat, and the caret-ranged `@radix-ui/*` tree via chat-components' `react-popover`. A changed direct dep that isn't webchat means unrelated drift got pulled in; drop it. Verify rather than eyeball a ~200-line diff: +Run this from `services/service-webchat` — the same directory as the `npm install` above. All three paths are relative to it, including git's `HEAD:./` prefix: + ```bash python3 - <<'EOF' import json, subprocess -old = json.loads(subprocess.run(['git','show','HEAD:services/service-webchat/package-lock.json'], +old = json.loads(subprocess.run(['git', 'show', 'HEAD:./package-lock.json'], capture_output=True, text=True).stdout) -new = json.loads(open('services/service-webchat/package-lock.json').read()) +new = json.loads(open('package-lock.json').read()) po, pn = old['packages'], new['packages'] changed = {k for k in set(po) | set(pn) if po.get(k, {}).get('version') != pn.get(k, {}).get('version')} -direct = set(json.loads(open('services/service-webchat/package.json').read()).get('dependencies', {})) +direct = set(json.loads(open('package.json').read()).get('dependencies', {})) print("direct deps changed:", sorted(k for k in changed if k.replace('node_modules/','') in direct)) print("total changed:", len(changed)) EOF ``` +Expect exactly `['node_modules/@cognigy/webchat']` as the direct change, against a total in the low tens. + The monorepo's pre-commit hooks (`pretty-quick`, `lint-staged`) only target `services/service-ui/**`, so they no-op here — but they do run, so don't mistake their output for an error. Open the PR titled `chore(service-webchat): update demo webchat to 3.NN.0`. ### 8c. After the QA green light — promote to `latest`