release: v5.2.0 — CC 2.1.114→181 compat + skill-listing budget (SKL)

New orchestrated scanner SKL (CA-SKL-001 1,536-char listing cap, CA-SKL-002
listing-budget sum) → 13 orchestrated scanners. Five validators refreshed for
the CC 2.1.114→181 settings/hook surface (xhigh effort, MessageDisplay +
post-session events). False positives eliminated in MCP and permissions
scanners. Hermetic HOME isolation across all CLI-spawning tests.

Version sync: plugin.json 5.1.0→5.2.0, README badges (version + tests-875+),
5 stale "12→13 scanners" prose fixes, What's New + version-history rewrite,
CHANGELOG [5.2.0] entry. 875/875 tests; self-audit configGrade A, pluginGrade A,
readmeCheck.passed:true.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ter3E2JSi1Khgmuf2kady8
This commit is contained in:
Kjell Tore Guttormsen 2026-06-18 20:37:45 +02:00
commit 157690993f
4 changed files with 230 additions and 57 deletions

View file

@ -1,7 +1,7 @@
{
"name": "config-audit",
"description": "Multi-agent workflow for analyzing, reporting, and optimizing Claude Code configuration across your entire machine",
"version": "5.1.0",
"version": "5.2.0",
"author": {
"name": "Kjell Tore Guttormsen"
},

View file

@ -5,6 +5,54 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [5.2.0] - 2026-06-18
### Summary
Claude Code 2.1.114→181 compatibility + skill-listing budget release. Adds a new
orchestrated scanner (SKL) for the model's skill-listing token budget, refreshes five
validators to recognize the settings/hook surface shipped across CC 2.1.114181, and
eliminates a batch of false positives surfaced by an adversarial gap-review. Scanner
internals only — no command, agent, or output-format changes.
### Added
- **`scanners/skill-listing-scanner.mjs` (SKL)** — new orchestrated deterministic scanner
(→ 13 orchestrated scanners). `CA-SKL-001` (medium): an active skill description over the
verified 1,536-char listing cap (CC 2.1.105) is silently truncated in the model's skill
listing. `CA-SKL-002` (low): the summed length of all active descriptions (each counted up
to the cap) over the listing budget (~2% of context, CC 2.1.32) — anchored on a conservative
200k window with a note that the budget scales 5× on 1M-context models; leads with the
measured sum, an estimate not telemetry. HOME-scoped (all user + plugin skills). Remediation
surfaces `disableBundledSkills` / `skillOverrides` / description trimming.
### Changed
- **settings-validator** — accepts CC 2.1.114181 settings keys and `xhigh` reasoning effort.
- **hook-validator** — recognizes `MessageDisplay` and post-session hook events (28 events).
- **claude-md-linter** — CLAUDE.md length reframed from a HIGH "adherence cliff" to a MEDIUM
token-cost finding (model-neutral, context-window aware).
- **tokens** — stale "Opus 4.7" framing refreshed to model-neutral with an Opus 4.8 anchor.
- **Knowledge corpus** — refreshed to the Opus 4.8 era (CC 2.1.114→181).
### Fixed
- **mcp-config-validator** — no longer flags auto-injected or POSIX-style env vars; removed an
invented `trust` field that does not exist in the MCP config schema.
- **permissions (DIS/CNF)** — dead-allow detection and conflict matching are now parameter-aware,
removing false positives on parameterized permission rules.
### Internal
- **Hermetic test isolation** — byte/snapshot tests and all 12 CLI-spawning test files now isolate
`HOME` via the `hermetic-home` helper, closing a leak class where the real `~/.claude` skills and
config bled into fixture-scoped runs (notably SKL, which is HOME-scoped regardless of
`includeGlobal`). Adversarially verified via a devil's-advocate gap-review pass.
### Test count
- 792 → 875 tests across 52 → 55 test files.
### Verification
- 875/875 tests pass (`node --test 'tests/**/*.test.mjs'`).
- `node scanners/self-audit.mjs --json --check-readme``configGrade: A` (96),
`pluginGrade: A` (100), `readmeCheck.passed: true`.
- README badge updated: `tests-792+``tests-875+`.
## [5.1.0] - 2026-05-01
### Summary

View file

@ -6,22 +6,22 @@
*AI-generated: all code produced by Claude Code through dialog-driven development. [Full disclosure →](../../README.md#ai-generated-code-disclosure)*
![Version](https://img.shields.io/badge/version-5.1.0-blue)
![Version](https://img.shields.io/badge/version-5.2.0-blue)
![Platform](https://img.shields.io/badge/platform-Claude_Code_Plugin-purple)
![Scanners](https://img.shields.io/badge/scanners-13-cyan)
![Commands](https://img.shields.io/badge/commands-18-green)
![Agents](https://img.shields.io/badge/agents-6-orange)
![Hooks](https://img.shields.io/badge/hooks-4-red)
![Tests](https://img.shields.io/badge/tests-792+-brightgreen)
![Tests](https://img.shields.io/badge/tests-875+-brightgreen)
![License](https://img.shields.io/badge/license-MIT-lightgrey)
A Claude Code plugin that checks configuration health, suggests context-aware improvements, and auto-fixes issues — `CLAUDE.md`, `settings.json`, hooks, rules, MCP servers, `@imports`, and plugins. 12 deterministic scanners across 10 quality areas, context-aware feature recommendations, auto-fix with backup/rollback, a prompt-cache-aware Token Hotspots scanner with optional API-calibrated `--accurate-tokens` mode, plus cache-prefix stability, dead-tool, and cross-plugin collision detection. Zero external dependencies.
A Claude Code plugin that checks configuration health, suggests context-aware improvements, and auto-fixes issues — `CLAUDE.md`, `settings.json`, hooks, rules, MCP servers, `@imports`, and plugins. 13 deterministic scanners across 10 quality areas, context-aware feature recommendations, auto-fix with backup/rollback, a prompt-cache-aware Token Hotspots scanner with optional API-calibrated `--accurate-tokens` mode, plus cache-prefix stability, dead-tool, and cross-plugin collision detection. Zero external dependencies.
---
## Table of Contents
- [What's New in v5.1.0](#whats-new-in-v510)
- [What's New in v5.2.0](#whats-new-in-v520)
- [What Is This?](#what-is-this)
- [The Configuration Problem](#the-configuration-problem)
- [Quick Start](#quick-start)
@ -45,56 +45,16 @@ A Claude Code plugin that checks configuration health, suggests context-aware im
---
## What's New in v5.1.0
## What's New in v5.2.0
**Plain-language UX humanizer** — every command's default output now leads with prose. Findings are grouped by what they mean for the user (Configuration mistake, Conflict, Wasted tokens, Missed opportunity, Dead config) and led with an urgency phrase (Fix this now, Fix soon, Fix when convenient, Optional cleanup, FYI). Technical IDs (`CA-CML-001`, `CA-TOK-005`, …) still appear, but at end-of-line where they belong as references rather than headlines.
### Before / after
```
v5.0.0 default
- [low] CA-CNF-001: Hook duplicate event registration
v5.1.0 default
- [low] The same automation is set up more than once
v5.1.0 with --json (machine-readable, byte-stable)
{ "id": "CA-CNF-001", "title": "...", "userImpactCategory": "Conflict",
"userActionLanguage": "Optional cleanup", "relevanceContext": "affects-everyone" }
```
### Plain-language vocabulary
The toolchain uses these terms when describing findings:
| User-facing label | What it means |
|-------------------|---------------|
| Fix this now | Something is broken or risky and should be addressed immediately |
| Fix soon | High-priority issue worth scheduling this week |
| Fix when convenient | Real issue but not urgent |
| Optional cleanup | Tidy-up that improves polish but isn't required |
| FYI | Informational; no action expected |
| Configuration mistake | A configuration file has an error or omission |
| Conflict | Two configuration sources disagree |
| Wasted tokens | Configuration is loading content that costs tokens without payback |
| Missed opportunity | A Claude Code feature you aren't using that could help your project |
| Dead config | Configuration that has no effect (e.g., a permission that's also denied) |
### Backwards compatibility — the `--raw` flag
Every CLI accepts `--raw` for byte-stable v5.0.0 verbatim output (technical IDs, raw severity, no prose translation). `--json` is unchanged from v5.0.0 — already byte-stable for programmatic consumption. Use `--raw` only if you've built tooling against v5.0.0 stderr scrapes; for new automation, prefer `--json`.
```bash
node scanners/posture.mjs . # v5.1.0 plain-language default
node scanners/posture.mjs . --raw # v5.0.0 verbatim (byte-stable)
node scanners/posture.mjs . --json # unchanged JSON envelope
```
### What's not changed
- All scanner internals (12 scanners + standalone PLH) emit the same finding IDs and structural data — humanization happens at output-formatting time only
- `--json` envelope shape is byte-stable with v5.0.0 (humanizer fields are additive on findings only in default mode; the `--json` path bypasses humanization entirely)
- 635 tests grew to 792 (+157 covering humanizer module, scenario read-tests, forbidden-words lint, JSON / `--raw` backwards-compat, default-output snapshots, and command-template / agent-prompt shape)
**Claude Code 2.1.114→181 compatibility + skill-listing budget.** A new orchestrated
scanner, **SKL**, checks the model's skill-listing token budget: `CA-SKL-001` flags any
active skill description over the 1,536-char listing cap (silently truncated by CC 2.1.105),
and `CA-SKL-002` flags when the summed descriptions exceed the listing budget (~2% of context).
Five validators were refreshed for the settings and hook surface that shipped across
CC 2.1.114181 (new settings keys, `xhigh` effort, `MessageDisplay` + post-session hook
events), and an adversarial gap-review eliminated a batch of false positives in the MCP and
permissions scanners. → **13 orchestrated deterministic scanners** (+ standalone plugin-health).
---
@ -104,7 +64,7 @@ Claude Code reads instructions from at least 7 different file types across multi
This plugin provides three layers of configuration intelligence:
- **Health** — 12 deterministic scanners verify correctness across every configuration file, catching broken imports, deprecated settings, conflicting rules, format errors, permission contradictions, prompt-cache token waste, cache-prefix instability, dead tool grants, and cross-plugin skill collisions
- **Health** — 13 deterministic scanners verify correctness across every configuration file, catching broken imports, deprecated settings, conflicting rules, format errors, permission contradictions, prompt-cache token waste, cache-prefix instability, dead tool grants, and cross-plugin skill collisions
- **Opportunities** — context-aware recommendations for Claude Code features that could benefit your specific project, backed by Anthropic's official guidance
- **Action** — auto-fix with mandatory backups, syntax validation, rollback support, and a human-in-the-loop workflow for anything non-trivial
@ -333,7 +293,7 @@ By default, `/config-audit` auto-detects scope from your git context. Override w
## Deterministic Scanners
12 Node.js scanners that perform structural analysis an LLM cannot reliably do: schema validation, circular reference detection, import resolution, conflict detection across scopes, prompt-cache-aware token-cost analysis, cache-prefix stability, dead-tool detection, and cross-plugin skill collisions. Plus a standalone plugin-health scanner. Zero external dependencies.
13 Node.js scanners that perform structural analysis an LLM cannot reliably do: schema validation, circular reference detection, import resolution, conflict detection across scopes, prompt-cache-aware token-cost analysis, cache-prefix stability, dead-tool detection, and cross-plugin skill collisions. Plus a standalone plugin-health scanner. Zero external dependencies.
**Why deterministic?** LLMs are powerful at understanding intent and context. But they cannot reliably validate JSON schemas, detect circular `@import` chains, or catch that your global `settings.json` contradicts your project-level one. These scanners fill that gap — fast, repeatable, and zero false positives on structural issues.
@ -474,7 +434,7 @@ node scanners/posture.mjs examples/optimal-setup/
### Self-Audit: Scanning the Scanner
The plugin runs all 12 scanners + the standalone plugin-health scanner on itself via `self-audit.mjs`. Test fixtures and example files are automatically excluded from scoring — a configuration plugin that ships deliberately broken examples shouldn't fail its own audit. Use `--check-readme` to verify badge counts are in sync with the filesystem.
The plugin runs all 13 scanners + the standalone plugin-health scanner on itself via `self-audit.mjs`. Test fixtures and example files are automatically excluded from scoring — a configuration plugin that ships deliberately broken examples shouldn't fail its own audit. Use `--check-readme` to verify badge counts are in sync with the filesystem.
```bash
node scanners/self-audit.mjs
@ -598,6 +558,7 @@ This plugin is cautious by design — configuration files are important, and a b
| Version | Date | Highlights |
|---------|------|-----------|
| **5.2.0** | 2026-06-18 | CC 2.1.114→181 compatibility + skill-listing budget. New orchestrated scanner **SKL** (`CA-SKL-001` 1,536-char listing cap, `CA-SKL-002` listing-budget sum) → 13 orchestrated scanners. Five validators refreshed for CC 2.1.114181 settings/hook surface (`xhigh` effort, `MessageDisplay` + post-session events, 28 hook events). False positives eliminated in MCP (auto-injected/POSIX env vars, invented `trust` field) and permissions (param-aware DIS/CNF). Hermetic HOME isolation across all CLI-spawning tests. 875 tests |
| **5.1.0** | 2026-05-01 | Plain-language UX humanizer. Default output of all 18 commands now leads with prose; findings grouped by user-impact category (Configuration mistake, Conflict, Wasted tokens, Missed opportunity, Dead config) and led by urgency phrase (Fix this now → FYI). New `--raw` flag preserves v5.0.0 verbatim output for tooling that scrapes stderr; `--json` is unchanged and byte-stable. New scanner-lib modules: `humanizer.mjs`, `humanizer-data.mjs` with TRANSLATIONS for 13 scanner prefixes. Self-audit terminal output also humanized. 792 tests (+157 humanizer-tester) |
| **5.0.0** | 2026-05-01 | Reality-based token-optimization. 3 new scanners (CPS cache-prefix, DIS dead tools, COL plugin collisions) → 12 deterministic scanners. New `/config-audit manifest` and `--accurate-tokens` API calibration. Severity-weighted scoring (`scoringVersion: 'v5'`). MCP token estimates 15 → 500+. Plugin Hygiene as 10th quality area. Knowledge: cache-stability replaces 200-line rule, cache-telemetry recipe. **Breaking:** F2 token magnitude jump, F3 severity weighting, F5 Pattern D removed, N1 `CA-TOK-*` glob now matches CA-TOK-005. 635 tests |
| **4.0.0** | 2026-04-19 | Opus 4.7 era: new TOK scanner (cache-breaking volatile content, redundant tool permissions, deep import chains, sonnet-era setups), `/config-audit tokens` command, Token Efficiency 8th quality area, scanner-agent + verifier-agent migrated haiku → sonnet. 543 tests |

164
docs/v5.2.0-release-plan.md Normal file
View file

@ -0,0 +1,164 @@
# v5.2.0 Release — Execution Plan
**Status:** ✅ EXECUTED 2026-06-18. All edits applied, verified (875/875 tests, self-audit
configGrade A / pluginGrade A / readmeCheck.passed:true), committed and tagged `v5.2.0`. This
doc is retained as the release record. Operator chose "v5.2.0-release first, then later sessions
for net-new capabilities" (2026-06-18).
Bump: **5.1.0 → 5.2.0** (minor: one new scanner + fixes, backward-compatible). 17 commits
since `v5.1.0` tag.
---
## Pre-verified facts (do NOT re-derive)
- **Tests: 875/875 pass, 0 fail**`node --test 'tests/**/*.test.mjs'`` tests 875 / pass 875 / fail 0` (run 2026-06-18, 15.99s). 55 test files (was 52 at v5.1.0).
- **Scanner count = 13 orchestrated.** `countScannerShape` in `self-audit.mjs` returns 13:
CML, SET, HKV, RUL, MCP, IMP, CNF, TOK, CPS, DIS, COL, GAP, **SKL**. PLH excluded (standalone).
Badge `scanners-13` already correct. SKL exports `scan` + wired into scan-orchestrator (line 66).
- **No `package.json`** in this plugin. Canonical version lives in `.claude-plugin/plugin.json`.
- **self-audit README gate** (`node scanners/self-audit.mjs --json --check-readme`): currently
`passed: false`, single mismatch `{kind: tests, expected: 875, foundInReadme: 792}`. configGrade A (96), pluginGrade A (100). Fixing the tests badge → gate passes.
- **SKL history:** at `v5.1.0` the badge was `scanners-12` + prose "12" (consistent). The SKL feat
commit (`7bb2547`) bumped badge 12→13 and updated docs/scanner-internals (14 prefixes) +
humanizer-data (14 TRANSLATIONS), **but missed the 5 README prose locations** still saying "12".
Fixing those is part of shipping SKL. (Version-history row for 5.0.0 at README:602 says "→ 12
deterministic scanners" — that is HISTORICAL, leave it.)
- **Push window:** weekday 20:0023:00 CEST, weekends/holidays anytime. Re-check `date '+%u %H:%M'`
immediately before push. (At plan time: Thu 20:24 → in window.)
---
## Edit targets
### 1. Version pointers (bump)
| File:line | Find → Replace |
|-----------|----------------|
| `.claude-plugin/plugin.json` (the `"version"` field) | `"version": "5.1.0"``"version": "5.2.0"` |
| `README.md:9` badge | `version-5.1.0-blue``version-5.2.0-blue` |
| `README.md:15` badge **(required for gate)** | `tests-792+-brightgreen``tests-875+-brightgreen` |
### 2. Stale-by-SKL prose: "12" → "13" orchestrated scanners (5 exact-match edits)
Badge `scanners-13` is already correct — do NOT touch the badge. Only these prose fragments:
- `README.md:18``12 deterministic scanners across 10 quality areas``13 deterministic scanners across 10 quality areas`
- `README.md:95``(12 scanners + standalone PLH)``(13 scanners + standalone PLH)`
- `README.md:107``12 deterministic scanners verify correctness``13 deterministic scanners verify correctness`
- `README.md:336``12 Node.js scanners that perform structural analysis``13 Node.js scanners that perform structural analysis`
- `README.md:477``runs all 12 scanners + the standalone plugin-health scanner``runs all 13 scanners + the standalone plugin-health scanner`
### 3. README "What's New" section + TOC
- `README.md:24` TOC — `- [What's New in v5.1.0](#whats-new-in-v510)``- [What's New in v5.2.0](#whats-new-in-v520)`
- `README.md:48100` — replace the ENTIRE "## What's New in v5.1.0" section (heading line 48
through line 100, i.e. up to but NOT including `## What Is This?` at line 101) with the
**What's New block** below. (Verify boundaries with `grep -n '^## ' README.md` before editing —
next `## ` heading after What's New marks the end.)
### 4. README version-history table — insert new row ABOVE the `**5.1.0**` row (currently README:601)
Use the **version-history row** below.
### 5. CHANGELOG.md — insert the `[5.2.0]` block ABOVE `## [5.1.0]` (currently CHANGELOG:8)
Use the **CHANGELOG block** below.
### Leave unchanged (historical-accurate)
- CLAUDE.md humanizer "(v5.1.0)" references (lines 65, 67) — describe when the humanizer landed.
- `docs/humanizer.md` "(v5.1.0)" references.
- README:602 (5.0.0 history row).
### Open decision (operator)
- `scanners/lib/humanizer-data.mjs:2` header comment "config-audit v5.1.0" — trivial; bump to
v5.2.0 for consistency OR leave. Not required for correctness. Default: leave unless operator says bump.
---
## New content blocks
### CHANGELOG block (insert above `## [5.1.0]`)
```markdown
## [5.2.0] - 2026-06-18
### Summary
Claude Code 2.1.114→181 compatibility + skill-listing budget release. Adds a new
orchestrated scanner (SKL) for the model's skill-listing token budget, refreshes five
validators to recognize the settings/hook surface shipped across CC 2.1.114181, and
eliminates a batch of false positives surfaced by an adversarial gap-review. Scanner
internals only — no command, agent, or output-format changes.
### Added
- **`scanners/skill-listing-scanner.mjs` (SKL)** — new orchestrated deterministic scanner
(→ 13 orchestrated scanners). `CA-SKL-001` (medium): an active skill description over the
verified 1,536-char listing cap (CC 2.1.105) is silently truncated in the model's skill
listing. `CA-SKL-002` (low): the summed length of all active descriptions (each counted up
to the cap) over the listing budget (~2% of context, CC 2.1.32) — anchored on a conservative
200k window with a note that the budget scales 5× on 1M-context models; leads with the
measured sum, an estimate not telemetry. HOME-scoped (all user + plugin skills). Remediation
surfaces `disableBundledSkills` / `skillOverrides` / description trimming.
### Changed
- **settings-validator** — accepts CC 2.1.114181 settings keys and `xhigh` reasoning effort.
- **hook-validator** — recognizes `MessageDisplay` and post-session hook events (28 events).
- **claude-md-linter** — CLAUDE.md length reframed from a HIGH "adherence cliff" to a MEDIUM
token-cost finding (model-neutral, context-window aware).
- **tokens** — stale "Opus 4.7" framing refreshed to model-neutral with an Opus 4.8 anchor.
- **Knowledge corpus** — refreshed to the Opus 4.8 era (CC 2.1.114→181).
### Fixed
- **mcp-config-validator** — no longer flags auto-injected or POSIX-style env vars; removed an
invented `trust` field that does not exist in the MCP config schema.
- **permissions (DIS/CNF)** — dead-allow detection and conflict matching are now parameter-aware,
removing false positives on parameterized permission rules.
### Internal
- **Hermetic test isolation** — byte/snapshot tests and all 12 CLI-spawning test files now isolate
`HOME` via the `hermetic-home` helper, closing a leak class where the real `~/.claude` skills and
config bled into fixture-scoped runs (notably SKL, which is HOME-scoped regardless of
`includeGlobal`). Adversarially verified via a devil's-advocate gap-review pass.
### Test count
- 792 → 875 tests across 52 → 55 test files.
### Verification
- 875/875 tests pass (`node --test 'tests/**/*.test.mjs'`).
- `node scanners/self-audit.mjs --json --check-readme``configGrade: A` (96),
`pluginGrade: A` (100), `readmeCheck.passed: true`.
- README badge updated: `tests-792+``tests-875+`.
```
### What's New block (replaces README:48100)
```markdown
## What's New in v5.2.0
**Claude Code 2.1.114→181 compatibility + skill-listing budget.** A new orchestrated
scanner, **SKL**, checks the model's skill-listing token budget: `CA-SKL-001` flags any
active skill description over the 1,536-char listing cap (silently truncated by CC 2.1.105),
and `CA-SKL-002` flags when the summed descriptions exceed the listing budget (~2% of context).
Five validators were refreshed for the settings and hook surface that shipped across
CC 2.1.114181 (new settings keys, `xhigh` effort, `MessageDisplay` + post-session hook
events), and an adversarial gap-review eliminated a batch of false positives in the MCP and
permissions scanners. → **13 orchestrated deterministic scanners** (+ standalone plugin-health).
```
### Version-history row (insert above the `**5.1.0**` row at README:601)
```markdown
| **5.2.0** | 2026-06-18 | CC 2.1.114→181 compatibility + skill-listing budget. New orchestrated scanner **SKL** (`CA-SKL-001` 1,536-char listing cap, `CA-SKL-002` listing-budget sum) → 13 orchestrated scanners. Five validators refreshed for CC 2.1.114181 settings/hook surface (`xhigh` effort, `MessageDisplay` + post-session events, 28 hook events). False positives eliminated in MCP (auto-injected/POSIX env vars, invented `trust` field) and permissions (param-aware DIS/CNF). Hermetic HOME isolation across all CLI-spawning tests. 875 tests |
```
---
## Verification (after edits, before commit)
1. `node scanners/self-audit.mjs --json --check-readme``readmeCheck.passed: true`, `mismatches: []`, configGrade A, pluginGrade A.
2. `grep -nc "12 deterministic\|(12 scanners +\|12 Node.js scanners\|all 12 scanners" README.md``0` (no stale current-state prose; the 5.0.0 history row at :602 is allowed and uses "→ 12 deterministic scanners" which these patterns do not match).
3. `node --test 'tests/**/*.test.mjs'` → 875/875, no snapshot drift.
4. `git diff tests/snapshots/` → empty (contamination check; grep for sadhguru/vegnorm/linkedin/ms-ai if any snapshot changed).
5. `grep version .claude-plugin/plugin.json``5.2.0`; README badges show `version-5.2.0` + `tests-875+`.
## Commit / tag / push
1. `git add -A` (CHANGELOG.md, README.md, .claude-plugin/plugin.json [+ humanizer-data.mjs if operator approved]).
2. Commit: `release: v5.2.0 — CC 2.1.114→181 compat + skill-listing budget (SKL)` + standard Co-Authored-By/Session trailers.
3. `git tag v5.2.0`.
4. **Re-check push window** `date '+%u %H:%M'`. In window (weekday 20:0023:00 / weekend / holiday) → `git push origin main && git push origin v5.2.0`. Out of window → hold both, tell operator when window opens.
5. After: overwrite STATE.md (release done), and the net-new-capabilities track becomes the next open item.