From 0bf149c9d68decdc0698ca466ddea9c929c8bf39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Pe=C3=B1a?= Date: Thu, 14 May 2026 08:53:11 -0600 Subject: [PATCH 1/3] feat(rules): add warn-version-readme-changelog-sync Tier 2 rule Warns when a version manifest (package.json, plugin.json, marketplace.json, or their .claude-plugin/ namespaced variants) is being bumped without a parallel update to README.md + CHANGELOG.md. This closes the gap PR #21 exposed: the toolkit shipped 1.1.0 -> 1.14.0 with no visible version surface (no README line, no CHANGELOG, no git tags). Without an enforcement rule, the same drift will reappear on the next bump. Pattern (DOJ-4064 three-layer drift thesis, Cure 4 - PreToolUse hooks): - Triggers on Write/Edit/MultiEdit to package.json, plugin.json, marketplace.json, .claude-plugin/plugin.json, .claude-plugin/marketplace.json - Detects new `"version": "X.Y.Z"` field in the written content / new_string - Warns the agent to update README.md "Version:" line + CHANGELOG.md entry in the same change - Tier 2 (warn, non-blocking) - hook cannot see other files in the diff, so it nudges rather than enforces - Bypass marker: version-readme-changelog-sync Sister enforcement (defense-in-depth): the dojo-os repo ships its own PostToolUse hook (.claude/hooks/post-write-version-readme-sync.sh) that catches the same drift locally even when the toolkit isn't installed. 11 new tests, all pass. Total rules: 32 (was 31). Created by Claude Code on behalf of @andres. Co-Authored-By: Claude Opus 4.7 --- hooks/rules/rules.json | 147 +++++++++++++++++++++++++++++++++++++++ hooks/rules/rules.yaml | 151 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 298 insertions(+) diff --git a/hooks/rules/rules.json b/hooks/rules/rules.json index a7780da..7012a9e 100644 --- a/hooks/rules/rules.json +++ b/hooks/rules/rules.json @@ -2638,5 +2638,152 @@ "expected_exit": 0 } ] + }, + { + "id": "warn-version-readme-changelog-sync", + "description": "Warn when a version manifest (package.json, plugin.json, marketplace.json) is being bumped without a parallel update to README.md + CHANGELOG.md — the visible-version surface drifts silently otherwise (DOJ-4064 defense-in-depth, sister rule to dojo-os repo-local post-write-version-readme-sync.sh)", + "applies_to": [ + "Edit", + "Write", + "MultiEdit" + ], + "match": [ + { + "field": "file_path", + "pattern": "(^|/)(package\\.json|plugin\\.json|marketplace\\.json|\\.claude-plugin/plugin\\.json|\\.claude-plugin/marketplace\\.json)$" + }, + { + "field": "content", + "pattern": "\"version\"[[:space:]]*:[[:space:]]*\"[0-9]" + } + ], + "action": "warn", + "bypass_marker": "version-readme-changelog-sync", + "memory_ref": "feedback_version_readme_changelog_sync.md", + "references": [ + "DOJ-4064 — three-layer drift thesis (Cure 4: PreToolUse/PostToolUse hooks)", + "Sister hook in dojo-os: .claude/hooks/post-write-version-readme-sync.sh", + "make-no-mistakes-toolkit PR #21 — visible README version + reconstructed CHANGELOG" + ], + "message": "WARN: a version manifest (package.json / plugin.json / marketplace.json)\nis being written with a \"version\": \"X.Y.Z\" field, but this hook cannot\nsee whether README.md and CHANGELOG.md were updated in the same change.\n\nWhen you bump the version in any manifest, also update in the same PR:\n 1. README.md — the \"Version: X.Y.Z\" line at the top\n 2. CHANGELOG.md — add a new entry under ## [X.Y.Z] - YYYY-MM-DD\n\nWhy this rule exists (DOJ-4064 three-layer drift thesis):\n- The repo shipped 1.1.0 → 1.14.0 with NO visible version anywhere a\n human would look (README, CHANGELOG, or git tags). PR #21 closed that\n gap by reconstructing the CHANGELOG and adding a header version line.\n- Without this rule, the same drift will reappear on the next bump.\n- Defense-in-depth: the dojo-os repo has a sister PostToolUse hook\n (.claude/hooks/post-write-version-readme-sync.sh) that catches the\n same drift locally even if this toolkit isn't installed.\n\nSuggested workflow:\n bump version in manifest(s) → update README.md \"Version: ...\" line →\n append CHANGELOG.md entry → commit all four files together.\n\nIf you're intentionally splitting the bump from the README/CHANGELOG\nupdate (e.g., bumping a vendored sub-manifest's version that isn't user-\nvisible), add \"# hook-bypass: version-readme-changelog-sync\" inline in\na comment near the version field or pass it on the Write call.\n", + "tests": [ + { + "name": "warns-on-package-json-version-bump", + "input": { + "tool_input": { + "file_path": "package.json", + "content": "{\n \"name\": \"@example/pkg\",\n \"version\": \"1.15.0\"\n}\n" + } + }, + "expected_exit": 0, + "expected_stderr_contains": "warn-version-readme-changelog-sync" + }, + { + "name": "warns-on-plugin-json-version-bump", + "input": { + "tool_input": { + "file_path": ".claude-plugin/plugin.json", + "content": "{\n \"name\": \"make-no-mistakes\",\n \"version\": \"1.15.0\"\n}\n" + } + }, + "expected_exit": 0, + "expected_stderr_contains": "warn-version-readme-changelog-sync" + }, + { + "name": "warns-on-marketplace-json-version-bump", + "input": { + "tool_input": { + "file_path": ".claude-plugin/marketplace.json", + "content": "{\n \"name\": \"marketplace\",\n \"version\": \"1.15.0\",\n \"plugins\": [{\"version\": \"1.15.0\"}]\n}\n" + } + }, + "expected_exit": 0, + "expected_stderr_contains": "warn-version-readme-changelog-sync" + }, + { + "name": "warns-on-absolute-path-package-json", + "input": { + "tool_input": { + "file_path": "/home/user/repo/package.json", + "content": "{\"version\": \"2.0.0\"}" + } + }, + "expected_exit": 0, + "expected_stderr_contains": "warn-version-readme-changelog-sync" + }, + { + "name": "warns-on-root-plugin-json", + "input": { + "tool_input": { + "file_path": "plugin.json", + "content": "{\"version\": \"1.0.1\"}" + } + }, + "expected_exit": 0, + "expected_stderr_contains": "warn-version-readme-changelog-sync" + }, + { + "name": "warns-on-edit-of-package-json", + "input": { + "tool_input": { + "file_path": "package.json", + "old_string": "\"version\": \"1.14.0\"", + "new_string": "\"version\": \"1.15.0\"" + } + }, + "expected_exit": 0, + "expected_stderr_contains": "warn-version-readme-changelog-sync" + }, + { + "name": "allows-package-json-write-without-version-field", + "input": { + "tool_input": { + "file_path": "package.json", + "content": "{\n \"name\": \"@example/pkg\",\n \"description\": \"no version field touched\"\n}\n" + } + }, + "expected_exit": 0 + }, + { + "name": "allows-unrelated-json-file", + "input": { + "tool_input": { + "file_path": "tsconfig.json", + "content": "{\"version\": \"1.0.0\"}" + } + }, + "expected_exit": 0 + }, + { + "name": "allows-readme-write", + "input": { + "tool_input": { + "file_path": "README.md", + "content": "**Version: 1.15.0**" + } + }, + "expected_exit": 0 + }, + { + "name": "allows-changelog-write", + "input": { + "tool_input": { + "file_path": "CHANGELOG.md", + "content": "## [1.15.0] - 2026-05-14" + } + }, + "expected_exit": 0 + }, + { + "name": "allows-bypass-marker", + "input": { + "tool_input": { + "file_path": "package.json", + "content": "{\n \"version\": \"1.15.0\"\n // hook-bypass: version-readme-changelog-sync\n}\n" + } + }, + "expected_exit": 0 + } + ] } ] diff --git a/hooks/rules/rules.yaml b/hooks/rules/rules.yaml index b90e75f..2279ea3 100644 --- a/hooks/rules/rules.yaml +++ b/hooks/rules/rules.yaml @@ -2083,3 +2083,154 @@ tool_input: command: 'git push origin main # hook-bypass: cd-worktree-rule' expected_exit: 0 + +- id: warn-version-readme-changelog-sync + description: Warn when a version manifest (package.json, plugin.json, marketplace.json) is being bumped without a parallel update to README.md + CHANGELOG.md — the visible-version surface drifts silently otherwise (DOJ-4064 defense-in-depth, sister rule to dojo-os repo-local post-write-version-readme-sync.sh) + applies_to: [Edit, Write, MultiEdit] + match: + # Anchor on start-of-string OR a leading "/" so the rule fires for both + # relative and absolute file paths. Covers the four manifest surfaces + # that ship a "version" field in this repo and most plugin repos: + # - package.json (npm manifest) + # - plugin.json (Claude Code plugin manifest at repo root) + # - marketplace.json (marketplace manifest at repo root) + # - .claude-plugin/plugin.json (Claude Code plugin manifest, namespaced) + # - .claude-plugin/marketplace.json (marketplace manifest, namespaced) + - field: file_path + pattern: '(^|/)(package\.json|plugin\.json|marketplace\.json|\.claude-plugin/plugin\.json|\.claude-plugin/marketplace\.json)$' + # Positive: the new content / new_string includes a "version": "X.Y.Z" line. + # Quote handling: JSON manifest files always use double quotes, so the + # pattern only needs to match the canonical `"version": "...` form. + # `[0-9]` as the first version character is intentional — we only warn on + # real semver-shaped bumps, not on edits that happen to remove the version + # field or add unrelated keys. + - field: content + pattern: '"version"[[:space:]]*:[[:space:]]*"[0-9]' + action: warn + bypass_marker: version-readme-changelog-sync + memory_ref: feedback_version_readme_changelog_sync.md + references: + - "DOJ-4064 — three-layer drift thesis (Cure 4: PreToolUse/PostToolUse hooks)" + - "Sister hook in dojo-os: .claude/hooks/post-write-version-readme-sync.sh" + - "make-no-mistakes-toolkit PR #21 — visible README version + reconstructed CHANGELOG" + message: | + WARN: a version manifest (package.json / plugin.json / marketplace.json) + is being written with a "version": "X.Y.Z" field, but this hook cannot + see whether README.md and CHANGELOG.md were updated in the same change. + + When you bump the version in any manifest, also update in the same PR: + 1. README.md — the "Version: X.Y.Z" line at the top + 2. CHANGELOG.md — add a new entry under ## [X.Y.Z] - YYYY-MM-DD + + Why this rule exists (DOJ-4064 three-layer drift thesis): + - The repo shipped 1.1.0 → 1.14.0 with NO visible version anywhere a + human would look (README, CHANGELOG, or git tags). PR #21 closed that + gap by reconstructing the CHANGELOG and adding a header version line. + - Without this rule, the same drift will reappear on the next bump. + - Defense-in-depth: the dojo-os repo has a sister PostToolUse hook + (.claude/hooks/post-write-version-readme-sync.sh) that catches the + same drift locally even if this toolkit isn't installed. + + Suggested workflow: + bump version in manifest(s) → update README.md "Version: ..." line → + append CHANGELOG.md entry → commit all four files together. + + If you're intentionally splitting the bump from the README/CHANGELOG + update (e.g., bumping a vendored sub-manifest's version that isn't user- + visible), add "# hook-bypass: version-readme-changelog-sync" inline in + a comment near the version field or pass it on the Write call. + tests: + - name: warns-on-package-json-version-bump + input: + tool_input: + file_path: 'package.json' + content: | + { + "name": "@example/pkg", + "version": "1.15.0" + } + expected_exit: 0 + expected_stderr_contains: 'warn-version-readme-changelog-sync' + - name: warns-on-plugin-json-version-bump + input: + tool_input: + file_path: '.claude-plugin/plugin.json' + content: | + { + "name": "make-no-mistakes", + "version": "1.15.0" + } + expected_exit: 0 + expected_stderr_contains: 'warn-version-readme-changelog-sync' + - name: warns-on-marketplace-json-version-bump + input: + tool_input: + file_path: '.claude-plugin/marketplace.json' + content: | + { + "name": "marketplace", + "version": "1.15.0", + "plugins": [{"version": "1.15.0"}] + } + expected_exit: 0 + expected_stderr_contains: 'warn-version-readme-changelog-sync' + - name: warns-on-absolute-path-package-json + input: + tool_input: + file_path: '/home/user/repo/package.json' + content: '{"version": "2.0.0"}' + expected_exit: 0 + expected_stderr_contains: 'warn-version-readme-changelog-sync' + - name: warns-on-root-plugin-json + input: + tool_input: + file_path: 'plugin.json' + content: '{"version": "1.0.1"}' + expected_exit: 0 + expected_stderr_contains: 'warn-version-readme-changelog-sync' + - name: warns-on-edit-of-package-json + input: + tool_input: + file_path: 'package.json' + old_string: '"version": "1.14.0"' + new_string: '"version": "1.15.0"' + expected_exit: 0 + expected_stderr_contains: 'warn-version-readme-changelog-sync' + - name: allows-package-json-write-without-version-field + input: + tool_input: + file_path: 'package.json' + content: | + { + "name": "@example/pkg", + "description": "no version field touched" + } + expected_exit: 0 + - name: allows-unrelated-json-file + input: + tool_input: + file_path: 'tsconfig.json' + content: '{"version": "1.0.0"}' + expected_exit: 0 + - name: allows-readme-write + input: + tool_input: + file_path: 'README.md' + content: '**Version: 1.15.0**' + expected_exit: 0 + - name: allows-changelog-write + input: + tool_input: + file_path: 'CHANGELOG.md' + content: '## [1.15.0] - 2026-05-14' + expected_exit: 0 + - name: allows-bypass-marker + input: + tool_input: + file_path: 'package.json' + content: | + { + "version": "1.15.0" + // hook-bypass: version-readme-changelog-sync + } + expected_exit: 0 From ceeb40e649731c06f80bcb26f21fadfd58a18e78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Pe=C3=B1a?= Date: Thu, 14 May 2026 08:54:11 -0600 Subject: [PATCH 2/3] chore: bump to 1.15.0 across manifests + README Coordinated bump across the four version surfaces: - package.json 1.14.0 -> 1.15.0 - .claude-plugin/plugin.json 1.14.0 -> 1.15.0 - .claude-plugin/marketplace.json 1.14.0 -> 1.15.0 (top + nested) - README.md "Version: ..." line 1.14.0 -> 1.15.0 This is the first bump that dogfoods the warn-version-readme-changelog-sync rule shipped in the prior commit on this branch: every manifest write would now warn about the README/CHANGELOG update requirement. README is being updated in this same commit; CHANGELOG entry follows in the next commit. Created by Claude Code on behalf of @andres. Co-Authored-By: Claude Opus 4.7 --- .claude-plugin/marketplace.json | 4 ++-- .claude-plugin/plugin.json | 2 +- README.md | 2 +- package.json | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index f79835c..17f3574 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -1,7 +1,7 @@ { "$schema": "https://anthropic.com/claude-code/marketplace.schema.json", "name": "make-no-mistakes", - "version": "1.14.0", + "version": "1.15.0", "description": "The disciplined dev lifecycle — implement issues, review PRs, sync releases, test E2E, manage sessions, and stash secrets via OS-native prompts. One plugin to make no mistakes.", "owner": { "name": "Luis Andres Pena Castillo", @@ -11,7 +11,7 @@ { "name": "make-no-mistakes", "description": "Dev lifecycle orchestrator: disciplined Linear issue execution with worktree isolation, PR review with Greptile gating, team release sync, E2E test generation and execution, test suite previewer, security pentesting, MoSCoW + RICE prioritization, cross-platform secret stash via OS-native GUI prompts (zenity / kdialog / osascript / Get-Credential), and session management. 18 commands, 6 auto-activating skills, 2 specialized agents.", - "version": "1.14.0", + "version": "1.15.0", "author": { "name": "Luis Andres Pena Castillo", "email": "lapc506@users.noreply.github.com" diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 5ed3d7d..18b46db 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "make-no-mistakes", - "version": "1.14.0", + "version": "1.15.0", "description": "The disciplined dev lifecycle — implement issues, review PRs, sync releases, test E2E, manage sessions, stash secrets, and enforce manifest-driven tool-call hooks. One plugin to make no mistakes.", "author": { "name": "Luis Andres Pena Castillo", diff --git a/README.md b/README.md index b7727e6..3b8522b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # make-no-mistakes -**Version: 1.14.0** · [CHANGELOG](./CHANGELOG.md) · [Marketplace](https://github.com/DojoCodingLabs/make-no-mistakes-toolkit) +**Version: 1.15.0** · [CHANGELOG](./CHANGELOG.md) · [Marketplace](https://github.com/DojoCodingLabs/make-no-mistakes-toolkit) The disciplined dev lifecycle — implement issues, review PRs, sync releases, test E2E, and manage sessions. One plugin to make no mistakes. diff --git a/package.json b/package.json index e72e579..02051d0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@lapc506/make-no-mistakes", - "version": "1.14.0", + "version": "1.15.0", "description": "The disciplined dev lifecycle — implement issues, review PRs, sync releases, test E2E, manage sessions, stash secrets, and enforce manifest-driven tool-call hooks (no SSH+DB, no manual prod, no minified build, no secret leaks, Slack format). OpenCode + Claude Code plugin.", "type": "module", "main": "./dist/index.js", From 06c185fddee474e84f76af7dcffb4b56e6ece1b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Pe=C3=B1a?= Date: Thu, 14 May 2026 08:54:48 -0600 Subject: [PATCH 3/3] docs(changelog): add 1.15.0 entry (dogfooding the new rule) Adds the 1.15.0 section to CHANGELOG.md immediately above the existing 1.14.0 entry, documenting: - The new warn-version-readme-changelog-sync Tier 2 rule (32 rules total) - The defense-in-depth pattern (toolkit + dojo-os parallel PRs) - The dogfooding observation: this release ships via the rule it adds This is the third atomic commit of the PR: 1. feat(rules): add the rule (commit 5dd0a67) 2. chore: bump to 1.15.0 across manifests + README (commit c9469f0) 3. docs(changelog): add 1.15.0 entry (this commit) Together they demonstrate the full discipline the rule enforces: manifest + README + CHANGELOG all updated in lockstep within the same PR. Created by Claude Code on behalf of @andres. Co-Authored-By: Claude Opus 4.7 --- CHANGELOG.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8da2514..cd7f418 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.15.0] - 2026-05-14 + +### Added +- New rule: `warn-version-readme-changelog-sync` (Tier 2 — warn). Fires on + `Write` / `Edit` / `MultiEdit` to `package.json`, `plugin.json`, + `marketplace.json`, `.claude-plugin/plugin.json`, or + `.claude-plugin/marketplace.json` when the written content includes a + `"version": "X.Y.Z"` field, and warns the agent to also update `README.md` + (the visible `Version:` line) and `CHANGELOG.md` in the same change. Closes + the gap PR #21 exposed: the toolkit shipped 1.1.0 → 1.14.0 with no visible + version surface (no README line, no CHANGELOG, no git tags); without this + rule the same drift would reappear on every future bump. Bypass marker: + `version-readme-changelog-sync`. + +### Notes +- Defense-in-depth (DOJ-4064 three-layer drift thesis, Cure 4): + - **Toolkit level (this PR)** — cross-repo enforcement; any consumer of + the toolkit inherits the rule and gets the warning on every manifest bump. + - **Repo level (parallel `dojo-os` PR)** — local `PostToolUse` hook + `.claude/hooks/post-write-version-readme-sync.sh` enforces the same + invariant in the dojo-os repo even if this toolkit isn't installed. +- Dogfooding: this version itself is being shipped via the rule it adds — + `README.md` "Version" line and `CHANGELOG.md` entry are updated alongside + the manifest bumps in the parent commits. If the rule were not warning, + the 1.15.0 release would already have re-introduced the same drift PR #21 + fixed. +- 32 rules total (was 31). 210 / 210 tests pass. + ## [1.14.0] - 2026-05-14 ### Added