cowork-harness 1.0.4 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,8 +3,8 @@ name: cowork-harness
3
3
  description: Test or debug a Claude Code skill/plugin under Claude Cowork's runtime — sandboxed agent, default-deny egress, the can_use_tool permission/question protocol — using the cowork-harness CLI. Use when validating or regression-testing a skill, authoring or debugging a scenario YAML (prompt + scripted answers + assert:), choosing a fidelity tier, scripting AskUserQuestion / tool-permission answers, or asserting artifacts, egress, or sub-agent dispatch. Especially when a harness run no-ops an assertion, fails on an unanswered gate, false-greens, a steered answer never reaches the model, or a web_fetch is unexpectedly denied or gated. NOT for generic unit testing (pytest/vitest of your own scripts) or non-Cowork CI. Covers the skill / run / chat / record / replay / trace / decide / assertions / scaffold commands and the session-vs-scenario split.
4
4
  metadata:
5
5
  author: cowork-harness
6
- version: 1.0.4
7
- tracks-harness: cowork-harness 1.0.4 (baseline desktop-1.20186.9)
6
+ version: 1.0.5
7
+ tracks-harness: cowork-harness 1.0.5 (baseline desktop-1.20186.9)
8
8
  ---
9
9
 
10
10
  # cowork-harness
@@ -22,7 +22,7 @@ flagged with a loud `::warning::`, not silent — auto-answer a gate, observe an
22
22
  allowlist). This skill exists mostly to keep you out of those traps — the Gotchas section below is
23
23
  the highest-value part. Read it.
24
24
 
25
- > **Version note:** the facts and `file:line` pointers here track `cowork-harness 1.0.4` (baseline
25
+ > **Version note:** the facts and `file:line` pointers here track `cowork-harness 1.0.5` (baseline
26
26
  > `desktop-1.20186.9`). If your checkout is newer, prefer the live `--help` and — in a repo checkout —
27
27
  > `SPEC.md` / `docs/*.md` over this snapshot, and re-run the bundled linter.
28
28
 
@@ -39,9 +39,9 @@ Before the first command, confirm the CLI is reachable and **fail loud** (never
39
39
 
40
40
  - **One-shot check.** Run `cowork-harness doctor [--tier <tier>]` first — a read-only prerequisite check that inspects Docker, the staged agent, the token, and the baseline in one pass. The bullets below explain each thing it checks (and how to fix it).
41
41
  - **Replay-only? Skip `doctor`.** Replaying committed cassettes needs no Docker, no staged agent, and no token — and every tier's `doctor` validates the auth token (the live tiers also Docker + the staged agent), so a ✗ there is expected, not a blocker. Go straight to `cowork-harness replay <cassette>`.
42
- - **CLI on PATH, recent enough?** Run `cowork-harness --version` — this skill needs **≥ 1.0.4**. If it's missing or older, prefix every command with the version floor `npx "cowork-harness@>=1.0.4" <cmd>` (Node ≥ 20), or install once with `npm i -g "cowork-harness@>=1.0.4"`. **Pin `@>=1.0.4`, never `@latest`** — `@latest` can silently fetch an older CLI and the new commands fail as "unknown command", whereas the floor **fails loud** if no compatible version is published.
42
+ - **CLI on PATH, recent enough?** Run `cowork-harness --version` — this skill needs **≥ 1.0.5**. If it's missing or older, prefix every command with the version floor `npx "cowork-harness@>=1.0.5" <cmd>` (Node ≥ 20), or install once with `npm i -g "cowork-harness@>=1.0.5"`. **Pin `@>=1.0.5`, never `@latest`** — `@latest` can silently fetch an older CLI and the new commands fail as "unknown command", whereas the floor **fails loud** if no compatible version is published.
43
43
 
44
- What the ≥ 1.0.4 floor gates, by release:
44
+ What the ≥ 1.0.5 floor gates, by release:
45
45
 
46
46
  - **core set (pre-0.21.0 vintage, or mixed):** `assertions --list`, `scaffold <run-id>`, `trace --view dispatches`, `artifact_json` incl. the `in:` operator (passes when the resolved value deep-equals one of the listed members — value ∈ your list, not the reverse), `verify-cassettes` incl. the `--allow-domain`/`--allow-email`/`--allow-patterns-file` allows (`--allow-patterns-file <path>` is a FILE of patterns, one regex per line — not a path to allow, unlike `--allow <regex>`), batch `record <dir>`/`--rerecord-stale`, `record --concurrency <N>`, record-time redaction, multiSelect/`answer:`, `verify-run` answer-coverage, `record --max-artifact-bytes`, live record-time deciders, scenario `skills:` staleness scoping with `COWORK_HARNESS_AGENT_SCOPE=skill`, `chat --plugin`, and `/help` in the REPL.
47
47
  - **0.21.0:** `verify-cassettes --allow-path` (`path` — local absolute filesystem paths — is the scanner's 4th class), and `hostloop`'s native host/VM process split with its `allow_host_writes:` consent field.
@@ -1,6 +1,6 @@
1
1
  # CI recipe — replay vs live lanes
2
2
 
3
- Self-contained reference. Tracks `cowork-harness 1.0.4` (baseline `desktop-1.20186.1`).
3
+ Self-contained reference. Tracks `cowork-harness 1.0.5` (baseline `desktop-1.20186.1`).
4
4
 
5
5
  **Fastest path: the packaged Action.** One step gets you `replay`/`lint`/`verify-cassettes` plus a PR
6
6
  job-summary reporter (verdict table, staleness findings, cost/turns when available):
@@ -13,7 +13,7 @@ job-summary reporter (verdict table, staleness findings, cost/turns when availab
13
13
  ```
14
14
 
15
15
  The Action's `version` input defaults to `latest` — intentional so a copy-pasted recipe tracks the current
16
- release; pin an exact version (e.g. `version: "1.0.4"`) for reproducible CI.
16
+ release; pin an exact version (e.g. `version: "1.0.5"`) for reproducible CI.
17
17
 
18
18
  Reach for the manual multi-step form below only when you need per-step control the Action's inputs don't
19
19
  cover (a custom flag combination, a different runner matrix per step, or `lint`/`verify-cassettes` gated
@@ -57,7 +57,7 @@ sha256-*checked* but not hard-blocking on mismatch — it's advisory for an inte
57
57
  GitHub-hosted runners, no token/Docker/agent:
58
58
 
59
59
  ```yaml
60
- - run: npm i -g "cowork-harness@>=1.0.4"
60
+ - run: npm i -g "cowork-harness@>=1.0.5"
61
61
  - run: cowork-harness lint scenarios/*.yaml # no silent false-greens
62
62
  - run: cowork-harness verify-cassettes cassettes/ # privacy + staleness
63
63
  - run: cowork-harness replay cassettes/ # token-free content/structure
@@ -197,7 +197,7 @@ jobs:
197
197
  with: { node-version: '20' }
198
198
  - uses: actions/setup-python@v5
199
199
  with: { python-version: '3.x' } # python3 only — PyYAML is bundled with the linter
200
- - run: npm i -g "cowork-harness@>=1.0.4"
200
+ - run: npm i -g "cowork-harness@>=1.0.5"
201
201
  - run: cowork-harness lint scenarios/*.yaml # no-silent-false-green (needs python3; PyYAML bundled)
202
202
  - run: cowork-harness verify-cassettes cassettes/ --output-format json # privacy + staleness gate
203
203
  - run: cowork-harness replay cassettes/ --output-format json # token-free content/structure
@@ -226,7 +226,7 @@ jobs:
226
226
  echo "live=true" >> "$GITHUB_OUTPUT"
227
227
  fi
228
228
  - if: steps.guard.outputs.live == 'true'
229
- run: npm i -g "cowork-harness@>=1.0.4"
229
+ run: npm i -g "cowork-harness@>=1.0.5"
230
230
  - if: steps.guard.outputs.live == 'true'
231
231
  run: cowork-harness run scenarios/ --output-format json
232
232
  env:
@@ -1,6 +1,6 @@
1
1
  # Fidelity tiers & answer paths
2
2
 
3
- Self-contained reference. Tracks `cowork-harness 1.0.4` (baseline `desktop-1.20186.1`).
3
+ Self-contained reference. Tracks `cowork-harness 1.0.5` (baseline `desktop-1.20186.1`).
4
4
 
5
5
  ## Fidelity tiers (`fidelity:` in the scenario)
6
6
 
@@ -1,6 +1,6 @@
1
1
  # Scenario & session schema, assertion catalog, web_fetch, full gotchas
2
2
 
3
- Self-contained reference for authoring `cowork-harness` scenarios. Tracks `cowork-harness 1.0.4`
3
+ Self-contained reference for authoring `cowork-harness` scenarios. Tracks `cowork-harness 1.0.5`
4
4
  (baseline `desktop-1.20186.1`). If your checkout is newer, prefer the live `docs/scenario.md`,
5
5
  `docs/session.md`, and `SPEC.md`.
6
6
 
package/CHANGELOG.md CHANGED
@@ -6,6 +6,29 @@ All notable changes to this project are documented here. The format is based on
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [1.0.5] — 2026-07-15
10
+
11
+ Patch: routine pushes to `main` no longer red CI on a repo without `ANTHROPIC_API_KEY` — the live
12
+ scenario suite is best-effort now — plus a CodeQL cleanup in the release tooling. Internal tooling +
13
+ CI only; no runtime or API change.
14
+
15
+ ### Changed
16
+
17
+ - `scripts/release-preflight.ts`: `changelogHasVersionSection` now finds the CHANGELOG heading with a
18
+ literal line-prefix match instead of a regex assembled from the version string. Behavior is
19
+ unchanged — the version is already `isValidSemver`-gated to `X.Y.Z` before this runs — and it drops
20
+ a redundant, only-partially-escaped regex flagged by CodeQL (`js/incomplete-sanitization`). Internal
21
+ release tooling only; no runtime or API change.
22
+ - **CI: the live scenario suite (`scenarios` job) is now best-effort, not a publish gate.** When
23
+ `ANTHROPIC_API_KEY` is absent it soft-skips green on every event — pushes to `main` included —
24
+ instead of hard-failing the run, so routine pushes to `main` (dependency bumps, docs, small fixes)
25
+ no longer turn CI red on a repo without the secret set. A loud `⚠️ NOT live-validated` marker still
26
+ flags any run that skipped live inference. The `SKIP_LIVE_SCENARIOS` admin-override variable is
27
+ removed (nothing hard-fails, so there is nothing to override). Trade-off: `release.yml` still gates
28
+ publish on `ci.yml` being green for the tagged commit, but a green `ci.yml` no longer proves the
29
+ scenarios were validated against a real model — set the `ANTHROPIC_API_KEY` repo secret to actually
30
+ run the live suite in CI. No runtime or API change.
31
+
9
32
  ## [1.0.4] — 2026-07-15
10
33
 
11
34
  Patch: release workflows no longer trigger on the floating Marketplace alias tags. No runtime/API change.
package/README.md CHANGED
@@ -91,7 +91,7 @@ node dist/cli.js replay examples/replays/example-pdf-skill.cassette.json
91
91
 
92
92
  > **Installed globally instead?** Once linked/installed, the same command is `cowork-harness replay
93
93
  > <cassette>` — but the relative path above only resolves from a source checkout's `examples/replays/`.
94
- > From a global install (`npm i -g "cowork-harness@>=1.0.4"`), point at the package root instead:
94
+ > From a global install (`npm i -g "cowork-harness@>=1.0.5"`), point at the package root instead:
95
95
  > `cowork-harness replay "$(npm root -g)/cowork-harness/examples/replays/example-pdf-skill.cassette.json"`
96
96
  > (or copy the cassette into your own project and pass that path).
97
97
 
@@ -101,7 +101,7 @@ Live `run`/`skill` need the prerequisites in the next section — note the `prot
101
101
  > - **Replay only (zero setup):** `cowork-harness replay <cassette>` — no token, no Docker, no agent. The command above.
102
102
  > - **`protocol` (real model, no Docker):** needs only the auth token (item 3 below).
103
103
  > - **Live `container` / `microvm` / `hostloop` / `cowork`:** needs Docker (or Lima for `microvm`), a staged agent, and the token — run `cowork-harness doctor` first.
104
- > - **Invocation:** from a source checkout, `node dist/cli.js <cmd>` (or `npm link` to get the `cowork-harness` command); from a global install, `cowork-harness <cmd>`; the companion skill falls back to `npx "cowork-harness@>=1.0.4"`.
104
+ > - **Invocation:** from a source checkout, `node dist/cli.js <cmd>` (or `npm link` to get the `cowork-harness` command); from a global install, `cowork-harness <cmd>`; the companion skill falls back to `npx "cowork-harness@>=1.0.5"`.
105
105
 
106
106
  Two more worked examples worth knowing about: `examples/scenarios/protocol-smoke.yaml` (zero-Docker smoke
107
107
  test) and `examples/scenarios/skill-loads.yaml` (container-tier acceptance check) — see
@@ -126,7 +126,7 @@ claude plugin marketplace add yaniv-golan/cowork-harness
126
126
  claude plugin install cowork-harness@cowork-harness
127
127
  ```
128
128
 
129
- The skill **self-bootstraps the CLI**: if `cowork-harness` isn't on your PATH it falls back to `npx "cowork-harness@>=1.0.4"` (a version floor that fails loud rather than silently fetching a too-old CLI; Node ≥ 20). Tiers above `protocol` still need Docker/Lima and a Claude Desktop agent binary — see the prerequisites below.
129
+ The skill **self-bootstraps the CLI**: if `cowork-harness` isn't on your PATH it falls back to `npx "cowork-harness@>=1.0.5"` (a version floor that fails loud rather than silently fetching a too-old CLI; Node ≥ 20). Tiers above `protocol` still need Docker/Lima and a Claude Desktop agent binary — see the prerequisites below.
130
130
 
131
131
  It also follows the open [Agent Skills](https://agentskills.io) spec, so it installs cross-editor (Cursor, Codex, OpenCode, …) via [`npx skills`](https://github.com/vercel-labs/skills) (Vercel Labs' CLI implementation of that spec):
132
132
 
@@ -147,7 +147,7 @@ A global install is enough for CI `lint`, reading the teaching skill, and replay
147
147
  To `run` the worked examples live or copy them as a starting point, use a source checkout. (The marketplace
148
148
  skill install itself only pulls `.claude/skills/cowork-harness/` — SKILL.md + `references/` + `scenario.py`/
149
149
  assertion keys, per `.claude-plugin/marketplace.json`'s `source` — not the rest of this table; the full set
150
- above becomes available once the skill's first command self-bootstraps `npx "cowork-harness@>=1.0.4"` — see
150
+ above becomes available once the skill's first command self-bootstraps `npx "cowork-harness@>=1.0.5"` — see
151
151
  [above](#drive-it-from-claude-code-companion-skill) — which pulls the same npm package as the global-install row.)
152
152
 
153
153
  ### Prerequisites for anything above `protocol` fidelity
@@ -665,7 +665,7 @@ jobs:
665
665
  anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
666
666
  ```
667
667
 
668
- Every run writes a Markdown verdict table (scenario, pass/fail, signals, cost/turns when available, staleness findings, and the replay-skipped-assertions honesty line) to the job summary. Inputs: `command`, `path` (required), `version` (npm dist-tag/version, default `latest` — intentional so recipes track the current release; pin an exact version for reproducible CI. The companion skill's `cowork-harness@>=1.0.4` floor guidance applies to ad-hoc CLI installs, not this input), `strict` (applies to `replay` (staleness findings), `lint`/`lint-skill` (WARN/INFO), and `analyze-skill` (any advisory finding); IGNORED — not forwarded — for `verify-cassettes`/`run`, which don't accept the flag), `fail-on-skill-drift` (**`replay`-only** — never forwarded to the analyzers), `extra-args`, `summary` (default `true`), `anthropic-api-key` (live lane only). See [`action.yml`](./action.yml) for the full input reference.
668
+ Every run writes a Markdown verdict table (scenario, pass/fail, signals, cost/turns when available, staleness findings, and the replay-skipped-assertions honesty line) to the job summary. Inputs: `command`, `path` (required), `version` (npm dist-tag/version, default `latest` — intentional so recipes track the current release; pin an exact version for reproducible CI. The companion skill's `cowork-harness@>=1.0.5` floor guidance applies to ad-hoc CLI installs, not this input), `strict` (applies to `replay` (staleness findings), `lint`/`lint-skill` (WARN/INFO), and `analyze-skill` (any advisory finding); IGNORED — not forwarded — for `verify-cassettes`/`run`, which don't accept the flag), `fail-on-skill-drift` (**`replay`-only** — never forwarded to the analyzers), `extra-args`, `summary` (default `true`), `anthropic-api-key` (live lane only). See [`action.yml`](./action.yml) for the full input reference.
669
669
 
670
670
  The provided [GitHub Actions workflow](.github/workflows/ci.yml) runs a **six-stage pipeline**. The **unit** stage is the token-free gate you can copy into your skill repo; the `action-self-test`, `python`, `boundary`, `scenarios`, and `parity-drift` stages are this repo's own fidelity self-tests and are not directly portable (they build the harness's Docker image and run harness-specific e2e scenarios — see [`ci-recipe.md`](./.claude/skills/cowork-harness/references/ci-recipe.md) for the skill-repo template):
671
671
 
package/RELEASING.md CHANGED
@@ -6,32 +6,18 @@ Pushing a `vX.Y.Z` tag triggers the `.github/workflows/release.yml` workflow, wh
6
6
  npm via **OIDC Trusted Publishing** (no stored token). Do **not** run `npm publish` manually — it
7
7
  requires an OTP and is not how this repo ships.
8
8
 
9
- ## Admin override — deliberately skipping the live scenario suite for one release
10
-
11
- The live scenario suite is part of the publish gate: on a canonical-repo push to `main` (the SHA
12
- `release.yml` gates on), `ci.yml` **hard-fails** if `ANTHROPIC_API_KEY` is missing, so a release can
13
- never silently publish without it. When you must ship a release without running the live suite (e.g.
14
- the key is temporarily unavailable), override it **explicitly and per-commit** — never by weakening the
15
- gate:
16
-
17
- 1. Set a repository **variable** (not a secret) named `SKIP_LIVE_SCENARIOS` to the **exact full commit
18
- SHA** you are releasing:
19
- ```
20
- gh variable set SKIP_LIVE_SCENARIOS --repo yaniv-golan/cowork-harness --body "<full-40-char-SHA>"
21
- ```
22
- The `ci.yml` guard skips the live suite (loud `::warning::ADMIN OVERRIDE`) **only** when this
23
- variable equals the running commit's SHA. Because it is pinned to one SHA, a later commit can never
24
- inherit the skip — the override auto-expires. Setting a repo variable requires admin, so the bypass
25
- is admin-gated and auditable in the run log.
26
- 2. Push that commit / re-run `ci.yml`; the scenario job now passes, so `require-ci-success` (the publish
27
- gate) is satisfied and the tag can publish.
28
- 3. **Unset it afterward** so the next release runs the live suite normally:
29
- ```
30
- gh variable delete SKIP_LIVE_SCENARIOS --repo yaniv-golan/cowork-harness
31
- ```
32
-
33
- This keeps the gate strict by default (a missing key still reds every un-overridden publish) while
34
- giving an admin a deliberate, one-release, logged escape hatch.
9
+ ## The live scenario suite is best-effort (not a publish gate)
10
+
11
+ The live scenario suite (the `scenarios` job in `ci.yml`) runs live inference only when
12
+ `ANTHROPIC_API_KEY` is available to the runner. Without the key it **soft-skips (green)** on every
13
+ event — pushes to `main` included — emitting a loud `⚠️ NOT live-validated` marker in the run summary.
14
+ It does **not** block the run and is **not** a publish gate: `release.yml`'s `require-ci-success` still
15
+ requires the `ci.yml` run for the tagged commit to be green, but a green run does not by itself prove
16
+ the scenarios were validated against a real model.
17
+
18
+ To actually run the live suite in CI, set the `ANTHROPIC_API_KEY` repo secret. There is no
19
+ `SKIP_LIVE_SCENARIOS` override — the suite never hard-fails on a missing key, so there is nothing to
20
+ override.
35
21
 
36
22
  ## The preferred three-phase sequence (branch → PR → merge → tag)
37
23
 
@@ -142,7 +128,7 @@ tagging `1.0.0`, deliberately review and freeze the surfaces with no machine-rea
142
128
  add that bullet by hand.
143
129
  - [ ] `npm run preflight` — local pre-release gate (`check:versions`, CHANGELOG heading present + non-empty,
144
130
  tag `vX.Y.Z` not already used, clean tree; warns if the `ANTHROPIC_API_KEY` repo secret is missing so
145
- the push-to-main live suite would need the `SKIP_LIVE_SCENARIOS` override — see §9).
131
+ the push-to-main live suite will soft-skip and this release won't be live-validated in CI).
146
132
  - [ ] `npm run format:check` — fix any issues (`npx prettier --write "src/**/*.ts" "test/**/*.ts"`).
147
133
  A format failure is the most common first-pass CI red.
148
134
  - [ ] `npx tsc -p tsconfig.test.json --noEmit` — typecheck including tests.
@@ -16,7 +16,7 @@ DOES exercise a real gate exchange, see `example-multiselect-gate.cassette.json`
16
16
 
17
17
  Run it with:
18
18
 
19
- > Assumes the `cowork-harness` CLI is available — from a source checkout run `npm ci && npm run build && npm link` first, or `npm i -g "cowork-harness@>=1.0.4"`. (`replay` itself needs nothing else — no token, no Docker.)
19
+ > Assumes the `cowork-harness` CLI is available — from a source checkout run `npm ci && npm run build && npm link` first, or `npm i -g "cowork-harness@>=1.0.5"`. (`replay` itself needs nothing else — no token, no Docker.)
20
20
 
21
21
  ```sh
22
22
  cowork-harness replay examples/replays/example-pdf-skill.cassette.json
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cowork-harness",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "Scriptable, CI-friendly harness for Claude Cowork's runtime contract for testing skills across scenarios — same agent, mounts, egress allowlist, permission protocol, and sandbox limitations.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -106,7 +106,7 @@
106
106
  "devDependencies": {
107
107
  "@types/node": "^26.0.0",
108
108
  "ajv": "^8.17.1",
109
- "prettier": "3.9.4",
109
+ "prettier": "3.9.5",
110
110
  "tsx": "^4.19.0",
111
111
  "typescript": "^6.0.3",
112
112
  "vitest": "^4.1.9"
@@ -10,7 +10,7 @@
10
10
  // stricter than release.yml — the section body is non-empty.
11
11
  // 3. The tag `v<version>` does not already exist, locally or on origin.
12
12
  // 4. The working tree is clean (`git status --porcelain` empty).
13
- // 5. Best-effort, WARN-only: nudge about the ANTHROPIC_API_KEY repo secret (live-suite gate).
13
+ // 5. Best-effort, WARN-only: nudge about the ANTHROPIC_API_KEY repo secret (the live suite runs only with it).
14
14
  // 6. --for-tag only, HARD fail: HEAD == origin/main HEAD, and a successful push-event ci.yml run
15
15
  // exists for HEAD — the exact check that would have caught the 0.33.0 mis-tag (tagging a
16
16
  // release-branch head instead of the merge commit).
@@ -35,17 +35,15 @@ export function isValidSemver(v: string): boolean {
35
35
  }
36
36
 
37
37
  /**
38
- * Mirrors release.yml's "Verify CHANGELOG has a heading for this version" step (a literal
39
- * `^## \[<version>\]` match, dots escaped) — plus a stricter, preflight-only requirement that the
40
- * section body (everything between this heading and the next `## [`) is non-empty. release.yml itself
41
- * does NOT require a non-empty body (its release-notes extraction step has its own fallback for that);
42
- * this function is intentionally stricter so an accidentally-empty section is caught before the tag.
38
+ * Mirrors release.yml's "Verify CHANGELOG has a heading for this version" step (an anchored
39
+ * `^## \[<version>\]` heading match) — implemented here as a literal line-prefix test on
40
+ * `## [<version>]`, so the version is matched verbatim (dots stay literal; no regex built from the
41
+ * version) — plus a stricter, preflight-only requirement that the section body (everything between
42
+ * this heading and the next `## [`) is non-empty. release.yml itself does NOT require a non-empty body
43
+ * (its release-notes extraction step has its own fallback for that); this function is intentionally
44
+ * stricter so an accidentally-empty section is caught before the tag.
43
45
  */
44
46
  export function changelogHasVersionSection(changelogText: string, version: string): boolean {
45
- const escaped = version.replace(/\./g, "\\.");
46
- const headingRe = new RegExp(`^## \\[${escaped}\\]`, "m");
47
- if (!headingRe.test(changelogText)) return false;
48
-
49
47
  const headingPrefix = `## [${version}]`;
50
48
  const lines = changelogText.split("\n");
51
49
  let inSection = false;
@@ -139,14 +137,15 @@ function checkWorkingTreeClean(): CheckResult {
139
137
  * Best-effort, WARN-only. `gh secret list` sees ONLY repo-level Actions secrets — an org- or
140
138
  * environment-level ANTHROPIC_API_KEY would false-warn here, and the call itself needs admin scope on
141
139
  * the repo. If `gh` is unavailable or unauthenticated, print the reminder unconditionally rather than
142
- * silently skipping — RELEASING.md §9 documents the SKIP_LIVE_SCENARIOS override.
140
+ * silently skipping. Without the key the live suite soft-skips in CI (it is not a publish gate) — see
141
+ * RELEASING.md.
143
142
  */
144
143
  function checkLiveSuiteKeyReminder(): CheckResult {
145
144
  const REMINDER =
146
- "if ANTHROPIC_API_KEY is not set as a repo secret, push-to-main ci will hard-fail the live scenario " +
147
- "suite — set the secret or plan the SKIP_LIVE_SCENARIOS override (RELEASING.md §9). Note: `gh secret " +
148
- "list` only sees repo-level Actions secrets — an org/environment secret would false-warn here, and the " +
149
- "call needs admin scope.";
145
+ "if ANTHROPIC_API_KEY is not set as a repo secret, the push-to-main live scenario suite soft-skips — " +
146
+ "this release won't be live-validated in CI (set the secret to run it; see RELEASING.md). Note: `gh " +
147
+ "secret list` only sees repo-level Actions secrets — an org/environment secret would false-warn here, " +
148
+ "and the call needs admin scope.";
150
149
 
151
150
  const ghVersion = run("gh", ["--version"]);
152
151
  if (!ghVersion.ok) {