diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 68b3c9d8..467c6141 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -9,7 +9,7 @@ "name": "uberdev", "source": "./plugins/uberdev", "description": "GitHub workflow commands + full Superpowers skill suite (brainstorm with visual companion, write-plan, execute-plan, subagent-driven-dev wave-based parallel execution, finish-branch, systematic-debugging, TDD, worktrees, parallel-agents, verification, code-review pair, writing-skills, using-uberdev primer) and PR review agents. /solve and /turbo dispatch autonomous agents via a platform-aware dispatch backend (Workflow-native solver fleets by default, with detached wezterm / background transports opt-in — cross-platform on macOS, Linux, WSL2, native Windows); /issue creates well-investigated, deduped issues.", - "version": "0.56.0", + "version": "0.56.1", "category": "workflow", "tags": [ "github", diff --git a/.gitignore b/.gitignore index d1a7576d..6e751545 100644 --- a/.gitignore +++ b/.gitignore @@ -74,8 +74,8 @@ id_rsa id_rsa.* .claude/ -# Personal, machine-local Claude instructions (CLAUDE.md itself is tracked — it -# only imports AGENTS.md, so worktrees and fresh clones load the project rules) +# Personal, machine-local Claude instructions (CLAUDE.md itself is tracked, so +# worktrees and fresh clones load the project rules) CLAUDE.local.md # Local implementation worktrees (write-plan / subagent-driven-dev) diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100644 index 51b79d7d..00000000 --- a/AGENTS.md +++ /dev/null @@ -1,67 +0,0 @@ -# AGENTS.md — UberDev (project-local) - -> Project-specific rules for the UberDev plugin repo. -> Inherits from `~/.codex/AGENTS.md`. Project rules win on conflict. - ---- - -## Bump version EVERYWHERE before merge (MANDATORY) - -**Every user-facing change MUST arrive on `main` with the project version advanced.** The invariant binds the **landing commit** — the commit that actually puts the change on `main` — not every pull request along the way. If users never see a version change they never pull the update from the marketplace, and the change is invisible to them no matter how good it is. - -Which commit that is depends on the lane the change came through, and one lane deliberately forbids the PR author from bumping at all. Check the lane before reading the diff. - -### Which commit carries the bump — the three lanes - -| Lane | Commit that carries the bump | What guarantees it | -|---|---|---| -| **`/goal`** | a `chore(release): vX.Y.Z` commit the pipeline pushes onto the PR branch on an **earlier pass** — the pass that pushes it deliberately withholds `/merge`, so the checks the push restarted can settle, and the dispatch happens on a later pass | `_uberdev_goal_ensure_version_bump` (`plugins/uberdev/lib/goal-state.sh`), called from the barrier-gated merge dispatch in `plugins/uberdev/lib/goal-watch.sh` (step 2c). It **fails closed**: any status it does not recognise as "bumped" withholds the `/merge` dispatch, and each failure stage it *does* recognise writes a `goal_merge_deferred` audit row with `reason=version_bump_failed` — the caller's catch-all arm withholds on an unrecognised status without writing a row of its own. Landing unbumped is the bug, so merging is never the fallback. | -| **`/solve` + `/turbo` fleet PRs** | the integration commit that lands the stack — `chore(stack): land #A #B … (vX.Y.Z)` — **once per stack**, never once per PR | `plugins/uberdev/skills/solve-fleet/workflow.js` tells every solver, in the dispatch prompt itself: *Do NOT bump the project version.* N solvers cut from one base all resolve the **same** next version; git auto-merges that identical edit with no conflict, so two intended releases collapse into one and a release is lost silently. | -| **Hand-authored PR landed directly** | the PR's own commits, or an immediately-preceding `chore(release): vX.Y.Z` commit on the same branch | the author. Nothing automated covers this lane. | - -**A fleet PR whose diff carries no version surface is compliant.** Its bump belongs to the landing commit, and `plugins/uberdev/skills/solve-fleet/workflow.js` forbids the solver from writing one — so reviewing such a PR as an unbumped user-facing change is a false positive, not a blocker. - -The lane carve-out governs **which commit carries the bump**, never **whether** a user-facing change may ship unbumped. **No exception for "small fixes" — even one-line patches get a patch-version bump on the commit that lands them.** - -### How to bump — one command, never by hand - -```bash -bash plugins/uberdev/lib/bump-version.sh -``` - -- Idempotent: re-running at the current version is a no-op success, no CHANGELOG churn. -- Refuses (exit 3) **before editing anything** when the surfaces already disagree — a half-bumped repo needs a human, not more `sed`. Every surface is re-grepped afterwards; a miss fails loudly (exit 4). -- **Never runs `git` or `gh`**: no commit, no tag, no push, no release. It edits files and prints the remaining ritual; the destructive steps stay in the operator's foreground. -- **Never parallel-bump.** Two PRs cut off the same base resolve the same next version. Decide land order first, then bump each one to the next free version as it lands (RFC 0012 §9). - -### Version locations (keep this list current) - -**Six file surfaces — all must agree, and `bump-version.sh` moves every one of them:** - -1. **`plugins/uberdev/.claude-plugin/plugin.json`** — `version` field (canonical source of truth; this is what `/plugin` reads). -2. **`.claude-plugin/marketplace.json`** — `plugins[0].version` field (what the marketplace listing shows). -3. **`README.md`** — top-of-file `![Version](https://img.shields.io/badge/version-X.Y.Z-blue)` badge. -4. **`CHANGELOG.md`** — new `## [X.Y.Z] — YYYY-MM-DD` section (Keep a Changelog 1.1.0 format; SemVer). The script inserts a dated stub; replace the placeholder with the real notes. -5. **`tests/goal.test.sh`** — the `G20: version bump locked (X.Y.Z)` block: one `assert_version_bump "$REPO_ROOT" ""` argument plus its echo header. -6. **`tests/solve-claim.test.sh`** — the `== Version bump A.B.C -> X.Y.Z propagated ==` block: the same one-argument shape. - -Surfaces 5 and 6 are the CI release-ratchet locks. They live in no manifest, so a missed bump sails through every local manifest check and still turns CI red on a clean `main`. - -**Two post-merge operator steps, by hand, only after the landing commit is on `main`:** - -7. **Git tag** — `git tag vX.Y.Z && git push origin vX.Y.Z`. -8. **GitHub Release** — `gh release create vX.Y.Z --title "vX.Y.Z" --notes-file ` so the Releases tab shows it. - -### Workflow - -- Pick the SemVer bump: `fix:` → patch, `feat:` → minor, breaking → major. -- Run `bash plugins/uberdev/lib/bump-version.sh `, fill in the CHANGELOG section, and put the result on whichever commit lands the change (see the lane table above). -- Verify the locks locally before pushing: `bash tests/goal.test.sh && bash tests/solve-claim.test.sh` (the authoritative full set is the run list in `.github/workflows/test.yml`). -- Tag and publish the release only once the landing commit is on `main` — one release per landing, sequentially. - -### Why this is a hard rule - -The marketplace manifest is what tells an installed plugin there is anything to pull. Without a bump the listing never changes and users keep running stale code. The README badge is the first thing a visitor sees — when it lags, the project reads as dead. - -And the ratchet is *equality*, not *advancement*: the two CI locks assert that the surfaces agree with each other at a hardcoded literal, not that the number went up. A landing that bumps nothing is consistently stale and stays green. Closing that gap in CI is tracked as issue **#386**; until then this rule, and the `/goal` guarantor above, are what stand in for it. - diff --git a/CHANGELOG.md b/CHANGELOG.md index 66403177..6a6b883b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,36 @@ All notable changes to UberDev are documented here. The format is based on [Keep a Changelog 1.1.0](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.56.1] — 2026-08-24 + +### Changed — the project rule file is `CLAUDE.md`, not `AGENTS.md` + +`AGENTS.md` was the Codex convention, reaching Claude Code only because a +one-line `CLAUDE.md` imported it (#748). This repo does not use Codex, so the +indirection bought nothing and cost a level of misdirection: the rules an agent +actually obeys lived in a file named for a tool that never reads this repo. + +The content is unchanged — the same bump-version-everywhere mandate, the same +three-lane table, the same six surfaces — it now lives directly in `CLAUDE.md`. +Nine citations that named the old path were retargeted: `bump-version.sh`, +`review-consolidate.sh`, the premerge SKILL (×2), RFC 0021, `docs/testing.md`, +`_lib_assert_structural.sh`, `post-impl-review/references/contracts.md`, and +`.gitignore`'s comment about the import that no longer exists. + +`tests/docs-accuracy.test.sh`'s T12 block — which FATALs on the rule document +being unreadable and pins fourteen assertions to its version section — was +retargeted with it. + +### Unchanged — reading a target repo's `AGENTS.md` + +The 62 remaining references are the plugin honouring **whatever** convention +file the repo it is installed into happens to carry. `convention-compliance` +reviews against the target repo's own written rules; `research-constraints` +reads `/AGENTS.md`; `review-fleet-args.sh` collects +`-name AGENTS.md -o -name CLAUDE.md -o -name .editorconfig`. Dropping those +would remove a feature from every downstream user, which is a different change +from this repo not needing the file itself. + ## [0.56.0] — 2026-08-24 Packs #762, #763, #764, #765 and #766 as one stack, plus three rounds of diff --git a/CLAUDE.md b/CLAUDE.md index 43c994c2..38befb78 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1 +1,67 @@ -@AGENTS.md +# CLAUDE.md — UberDev (project-local) + +> Project-specific rules for the UberDev plugin repo. +> Inherits from `~/.claude/CLAUDE.md`. Project rules win on conflict. + +--- + +## Bump version EVERYWHERE before merge (MANDATORY) + +**Every user-facing change MUST arrive on `main` with the project version advanced.** The invariant binds the **landing commit** — the commit that actually puts the change on `main` — not every pull request along the way. If users never see a version change they never pull the update from the marketplace, and the change is invisible to them no matter how good it is. + +Which commit that is depends on the lane the change came through, and one lane deliberately forbids the PR author from bumping at all. Check the lane before reading the diff. + +### Which commit carries the bump — the three lanes + +| Lane | Commit that carries the bump | What guarantees it | +|---|---|---| +| **`/goal`** | a `chore(release): vX.Y.Z` commit the pipeline pushes onto the PR branch on an **earlier pass** — the pass that pushes it deliberately withholds `/merge`, so the checks the push restarted can settle, and the dispatch happens on a later pass | `_uberdev_goal_ensure_version_bump` (`plugins/uberdev/lib/goal-state.sh`), called from the barrier-gated merge dispatch in `plugins/uberdev/lib/goal-watch.sh` (step 2c). It **fails closed**: any status it does not recognise as "bumped" withholds the `/merge` dispatch, and each failure stage it *does* recognise writes a `goal_merge_deferred` audit row with `reason=version_bump_failed` — the caller's catch-all arm withholds on an unrecognised status without writing a row of its own. Landing unbumped is the bug, so merging is never the fallback. | +| **`/solve` + `/turbo` fleet PRs** | the integration commit that lands the stack — `chore(stack): land #A #B … (vX.Y.Z)` — **once per stack**, never once per PR | `plugins/uberdev/skills/solve-fleet/workflow.js` tells every solver, in the dispatch prompt itself: *Do NOT bump the project version.* N solvers cut from one base all resolve the **same** next version; git auto-merges that identical edit with no conflict, so two intended releases collapse into one and a release is lost silently. | +| **Hand-authored PR landed directly** | the PR's own commits, or an immediately-preceding `chore(release): vX.Y.Z` commit on the same branch | the author. Nothing automated covers this lane. | + +**A fleet PR whose diff carries no version surface is compliant.** Its bump belongs to the landing commit, and `plugins/uberdev/skills/solve-fleet/workflow.js` forbids the solver from writing one — so reviewing such a PR as an unbumped user-facing change is a false positive, not a blocker. + +The lane carve-out governs **which commit carries the bump**, never **whether** a user-facing change may ship unbumped. **No exception for "small fixes" — even one-line patches get a patch-version bump on the commit that lands them.** + +### How to bump — one command, never by hand + +```bash +bash plugins/uberdev/lib/bump-version.sh +``` + +- Idempotent: re-running at the current version is a no-op success, no CHANGELOG churn. +- Refuses (exit 3) **before editing anything** when the surfaces already disagree — a half-bumped repo needs a human, not more `sed`. Every surface is re-grepped afterwards; a miss fails loudly (exit 4). +- **Never runs `git` or `gh`**: no commit, no tag, no push, no release. It edits files and prints the remaining ritual; the destructive steps stay in the operator's foreground. +- **Never parallel-bump.** Two PRs cut off the same base resolve the same next version. Decide land order first, then bump each one to the next free version as it lands (RFC 0012 §9). + +### Version locations (keep this list current) + +**Six file surfaces — all must agree, and `bump-version.sh` moves every one of them:** + +1. **`plugins/uberdev/.claude-plugin/plugin.json`** — `version` field (canonical source of truth; this is what `/plugin` reads). +2. **`.claude-plugin/marketplace.json`** — `plugins[0].version` field (what the marketplace listing shows). +3. **`README.md`** — top-of-file `![Version](https://img.shields.io/badge/version-X.Y.Z-blue)` badge. +4. **`CHANGELOG.md`** — new `## [X.Y.Z] — YYYY-MM-DD` section (Keep a Changelog 1.1.0 format; SemVer). The script inserts a dated stub; replace the placeholder with the real notes. +5. **`tests/goal.test.sh`** — the `G20: version bump locked (X.Y.Z)` block: one `assert_version_bump "$REPO_ROOT" ""` argument plus its echo header. +6. **`tests/solve-claim.test.sh`** — the `== Version bump A.B.C -> X.Y.Z propagated ==` block: the same one-argument shape. + +Surfaces 5 and 6 are the CI release-ratchet locks. They live in no manifest, so a missed bump sails through every local manifest check and still turns CI red on a clean `main`. + +**Two post-merge operator steps, by hand, only after the landing commit is on `main`:** + +7. **Git tag** — `git tag vX.Y.Z && git push origin vX.Y.Z`. +8. **GitHub Release** — `gh release create vX.Y.Z --title "vX.Y.Z" --notes-file ` so the Releases tab shows it. + +### Workflow + +- Pick the SemVer bump: `fix:` → patch, `feat:` → minor, breaking → major. +- Run `bash plugins/uberdev/lib/bump-version.sh `, fill in the CHANGELOG section, and put the result on whichever commit lands the change (see the lane table above). +- Verify the locks locally before pushing: `bash tests/goal.test.sh && bash tests/solve-claim.test.sh` (the authoritative full set is the run list in `.github/workflows/test.yml`). +- Tag and publish the release only once the landing commit is on `main` — one release per landing, sequentially. + +### Why this is a hard rule + +The marketplace manifest is what tells an installed plugin there is anything to pull. Without a bump the listing never changes and users keep running stale code. The README badge is the first thing a visitor sees — when it lags, the project reads as dead. + +And the ratchet is *equality*, not *advancement*: the two CI locks assert that the surfaces agree with each other at a hardcoded literal, not that the number went up. A landing that bumps nothing is consistently stale and stays green. Closing that gap in CI is tracked as issue **#386**; until then this rule, and the `/goal` guarantor above, are what stand in for it. + diff --git a/README.md b/README.md index 09e2e8df..30db5aae 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ **Personal Claude Code marketplace — opinionated GitHub-workflow slash commands.** -[![Version](https://img.shields.io/badge/version-0.56.0-blue)](./CHANGELOG.md) +[![Version](https://img.shields.io/badge/version-0.56.1-blue)](./CHANGELOG.md) [![License](https://img.shields.io/badge/license-MIT-green)](./LICENSE) [![Claude Code](https://img.shields.io/badge/Claude%20Code-plugin-8B5CF6)](https://docs.claude.com/en/docs/claude-code/plugins) [![Repo Agnostic](https://img.shields.io/badge/repo--agnostic-yes-success)](#configuration) diff --git a/docs/rfc/0021-premerge-stack-integration.md b/docs/rfc/0021-premerge-stack-integration.md index 2eb910c3..4659ecb5 100644 --- a/docs/rfc/0021-premerge-stack-integration.md +++ b/docs/rfc/0021-premerge-stack-integration.md @@ -52,7 +52,7 @@ to any per-PR review: 1. **Version collision.** N PRs cut from one base all resolve the same next version. Git auto-merges the identical edit with no conflict, so two intended - releases silently collapse into one. `AGENTS.md` already responds by binding + releases silently collapse into one. `CLAUDE.md` already responds by binding the bump to the *landing commit* and forbidding PR authors from bumping — which leaves an obvious gap: *something* has to do the bump, once, at landing time. Nothing did. `/premerge` Phase 5 is that something. diff --git a/plugins/uberdev/.claude-plugin/plugin.json b/plugins/uberdev/.claude-plugin/plugin.json index ad0ad569..b3ac2d79 100644 --- a/plugins/uberdev/.claude-plugin/plugin.json +++ b/plugins/uberdev/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "uberdev", - "version": "0.56.0", + "version": "0.56.1", "description": "Production-grade Claude Code plugin: parallel-fanout PR review, autonomous GitHub issue triage and resolution via Workflow-native solver fleets (one worktree-isolated agent per issue; detached wezterm / background transports remain opt-in; cross-platform — macOS, Linux, WSL2, native Windows), brainstorm/plan/execute workflows with wave-based subagent dispatch.", "author": { "name": "TheFJK", diff --git a/plugins/uberdev/docs/testing.md b/plugins/uberdev/docs/testing.md index 3bab55c2..bda6d3b5 100644 --- a/plugins/uberdev/docs/testing.md +++ b/plugins/uberdev/docs/testing.md @@ -59,7 +59,7 @@ These are **structural / contract** checks, not end-to-end behavioural tests of - **Prompt-file contracts** — that a command or agent file still names every dispatch slot, every required flag, every documented argument, and every guard rail it is supposed to (e.g. `review-pr.test.sh` asserts the seven Phase-1 reviewers run in one or more cap-controlled waves, with every child in each wave dispatched before its first wait). - **Runtime behavioural fixtures** — a subset `source` a real `lib/` helper and assert its output. Examples: `solve-pipeline-zsh.test.sh` (zsh word-splitting), `goal.test.sh` BT84 / BT85 (goal-pipeline behaviour), `config-override.test.sh` (config precedence), `secret-scan.test.sh` (the pre-push scanner). So the suite is **not** purely static — the claim "no behavioural tests" is false. -- **Release-ratchet version locks** — `goal.test.sh` (the `G20: version bump locked` block) and `solve-claim.test.sh` (the `Version bump A.B.C -> X.Y.Z propagated` block) hardcode the current version and **turn CI red on a missed bump**. They are part of the mandatory bump-everywhere ritual (see the root `AGENTS.md`, "Bump version EVERYWHERE before merge"). A contributor who skips the full suite skips exactly the tests that catch a forgotten version bump. +- **Release-ratchet version locks** — `goal.test.sh` (the `G20: version bump locked` block) and `solve-claim.test.sh` (the `Version bump A.B.C -> X.Y.Z propagated` block) hardcode the current version and **turn CI red on a missed bump**. They are part of the mandatory bump-everywhere ritual (see the root `CLAUDE.md`, "Bump version EVERYWHERE before merge"). A contributor who skips the full suite skips exactly the tests that catch a forgotten version bump. - **CI-wiring invariant** — `tests/ci-wiring.test.sh` asserts that *every* `tests/*.test.sh` on disk is wired into the workflow, so a new test that is forgotten in `test.yml` fails CI rather than silently never running. They deliberately do **not** launch real `claude` sessions, parse session transcripts, or measure token usage. UberDev ships no headless-integration runner and no token-analysis script — the suite is the `tests/*.test.sh` shape-checks (plus the helper files they drive: `tests/_lib_assert_structural.sh`, `tests/_workflow_harness.js`) and nothing else. @@ -173,4 +173,4 @@ Conventions worth honouring: - `tests/_lib_exit_floor.sh` — the anti-vacuity exit floor, with the measured bash-3.2-vs-5 status table. - `tests/_workflow_harness.js` — the T1–T4 workflow-script harness (self-tests: `node tests/_workflow_harness.js self-test`). - RFC 0012 (ultracode workflow migration, `docs/rfc/`) — defines the workflow-script conventions the T1–T4 tier enforces. -- The root `AGENTS.md` — the bump-version-everywhere ritual the version-lock tests enforce, and which commit in each lane carries the bump. +- The root `CLAUDE.md` — the bump-version-everywhere ritual the version-lock tests enforce, and which commit in each lane carries the bump. diff --git a/plugins/uberdev/lib/bump-version.sh b/plugins/uberdev/lib/bump-version.sh index 44c4c7c3..fd90c028 100644 --- a/plugins/uberdev/lib/bump-version.sh +++ b/plugins/uberdev/lib/bump-version.sh @@ -43,7 +43,7 @@ # foreground control over the destructive tag/release steps stays with # the operator, serialized against /merge landings (RFC 0012 §7.7). The # ritual itself — including which commit carries the bump in each of the -# three lanes — is documented in the repo-root AGENTS.md ("Bump version +# three lanes — is documented in the repo-root CLAUDE.md ("Bump version # EVERYWHERE before merge"). The checklist is ALSO printed here because # the operator's local CLAUDE.md twin is gitignored, so it exists in no # fresh checkout and in no worktree an agent runs in (R-15). diff --git a/plugins/uberdev/lib/review-consolidate.sh b/plugins/uberdev/lib/review-consolidate.sh index 17768415..70520efa 100644 --- a/plugins/uberdev/lib/review-consolidate.sh +++ b/plugins/uberdev/lib/review-consolidate.sh @@ -1119,7 +1119,7 @@ EOF_CONSOLIDATE_CLOSES } # review_consolidate_title SCAN_DIR -> `chore(stack): land #A #B …` -# The shape AGENTS.md blesses for a fleet PR. The `(vX.Y.Z)` suffix and the +# The shape CLAUDE.md blesses for a fleet PR. The `(vX.Y.Z)` suffix and the # version bump belong to the LANDING commit, once per stack -- not here. review_consolidate_title() { [ "$#" -eq 1 ] || return 2 diff --git a/plugins/uberdev/skills/post-impl-review/references/contracts.md b/plugins/uberdev/skills/post-impl-review/references/contracts.md index 7d47aadb..9deec305 100644 --- a/plugins/uberdev/skills/post-impl-review/references/contracts.md +++ b/plugins/uberdev/skills/post-impl-review/references/contracts.md @@ -86,7 +86,7 @@ cull would take another lens's finding with it): - the quote is verified verbatim against the cited file's own bytes, within a bounded window of the cited line, after whitespace normalisation; - a cited path outside the allowlist is never opened at all; -- a rule is scoped to its own directory subtree — `plugins/x/AGENTS.md` does not +- a rule is scoped to its own directory subtree — `plugins/x/CLAUDE.md` does not govern `tools/`; - a quote that is secret-shaped, too short to cite anything, or longer than the contract's 300-character carve-out is refused; diff --git a/plugins/uberdev/skills/premerge-pipeline/SKILL.md b/plugins/uberdev/skills/premerge-pipeline/SKILL.md index 1576deac..6a55260c 100644 --- a/plugins/uberdev/skills/premerge-pipeline/SKILL.md +++ b/plugins/uberdev/skills/premerge-pipeline/SKILL.md @@ -2319,7 +2319,7 @@ always yes, and never "does this repo have a version ratchet", which is the question. The repo-kind signal is a path in the target tree, and it is the same signal `/goal` already uses. -**Why the bump belongs here and nowhere else.** `AGENTS.md` binds the version to +**Why the bump belongs here and nowhere else.** `CLAUDE.md` binds the version to the *landing commit*, once per stack — and forbids the individual PR authors from bumping precisely because N PRs cut from one base all resolve the **same** next version, git auto-merges the identical edit without a conflict, and two intended @@ -2398,7 +2398,7 @@ Then replace the CHANGELOG stub with real notes derived from the packed PR title `chore(release): v`, and push. **Do not tag and do not create a GitHub Release.** Both are post-merge operator -steps in `AGENTS.md`, and both would be wrong on a branch that has not landed. +steps in `CLAUDE.md`, and both would be wrong on a branch that has not landed. ### 5b — PARK diff --git a/tests/_lib_assert_structural.sh b/tests/_lib_assert_structural.sh index 128bd084..a0c016a2 100755 --- a/tests/_lib_assert_structural.sh +++ b/tests/_lib_assert_structural.sh @@ -228,7 +228,7 @@ _assert_version_bump_one() { # # test-lock files (tests/goal.test.sh, tests/solve-claim.test.sh) are NOT # asserted here — they are this helper's own call sites, and # plugins/uberdev/lib/bump-version.sh is what moves them. Six file surfaces in -# total; the repo-root AGENTS.md is the SSOT for the list. +# total; the repo-root CLAUDE.md is the SSOT for the list. assert_version_bump() { local root="$1" ver="$2" local v="${ver//./\\.}" # escape dots so grep -E matches them literally diff --git a/tests/docs-accuracy.test.sh b/tests/docs-accuracy.test.sh index 609faf8c..5abb0dca 100644 --- a/tests/docs-accuracy.test.sh +++ b/tests/docs-accuracy.test.sh @@ -72,13 +72,13 @@ PLUGIN_DIR="$REPO_ROOT/plugins/uberdev" HOOKS_JSON="$REPO_ROOT/plugins/uberdev/hooks/hooks.json" HOOKS_CURSOR_JSON="$REPO_ROOT/plugins/uberdev/hooks/hooks-cursor.json" PRE_COMPACT="$REPO_ROOT/plugins/uberdev/hooks/pre-compact" -# #472 version-bump-contract surfaces. AGENTS.md is the rule document the +# #472 version-bump-contract surfaces. CLAUDE.md is the rule document the # convention lens quotes verbatim AND the only one a worktree solver can read # (the project CLAUDE.md twin is gitignored — .gitignore). The other three are # the machinery that decides which commit actually carries the bump, so T12 # below locks the doc and the machinery against EACH OTHER rather than pinning # either alone. -AGENTS_MD="$REPO_ROOT/AGENTS.md" +CLAUDE_MD="$REPO_ROOT/CLAUDE.md" SOLVE_FLEET_JS="$PLUGIN_DIR/skills/solve-fleet/workflow.js" # #507 design-chain surfaces. The fleet script is the machinery; its SKILL.md # and RFC 0015 both restate the chain AND the CB1 projection as prose, so T14 @@ -128,7 +128,7 @@ for f in "$TESTING_MD" "$CONTRIBUTING_MD" "$DISPATCH_RFC" "$ALIAS_RFC" \ "$SESSION_START" "$ALIASES_SYNC" "$TEST_YML" \ "$USING_SKILL" "$CONFIG_REF" "$HOOKS_JSON" "$HOOKS_CURSOR_JSON" \ "$PRE_COMPACT" "$WORKFLOW_RFC" "$GOAL_RFC" "$VENDOR_RFC" \ - "$PRECISION_RFC" "$PRECISION_MINER" "$AGENTS_MD" "$SOLVE_FLEET_JS" \ + "$PRECISION_RFC" "$PRECISION_MINER" "$CLAUDE_MD" "$SOLVE_FLEET_JS" \ "$SOLVE_FLEET_SKILL" "$DISPATCH15_RFC" "$MERGE_PIPELINE_SKILL" \ "$GOAL_WATCH_SH" "$BUMP_VERSION_SH" "$STRUCTURAL_LIB" \ "$ADAPTIVE_RFC" "$RUN_MANIFEST_PY" "$DOCS_ACCURACY_SELF" \ @@ -139,8 +139,8 @@ done # Shared structural-assertion helpers (assert_in_section + assert_count for T12 # — the version rule is sliced to its own section so a stray prose match -# elsewhere in AGENTS.md cannot false-positive it; see the T12 block for what -# that scoping does and does NOT buy while AGENTS.md carries a single level-2 +# elsewhere in CLAUDE.md cannot false-positive it; see the T12 block for what +# that scoping does and does NOT buy while CLAUDE.md carries a single level-2 # section). Fail-loud guard per #209: a missing or unreadable helper aborts # rc=2, never vacuous-green. source "$REPO_ROOT/tests/_lib_assert_structural.sh" || { echo "FATAL: _lib_assert_structural.sh missing/unreadable" >&2; exit 2; } @@ -1927,14 +1927,14 @@ assert_grep "$REPO_ROOT/README.md" 'finding-confidence-rubric-v1' \ echo echo "== T12: the version-bump contract — rule doc and machinery, locked in both directions (#472) ==" -# THE DRIFT THIS LOCKS. AGENTS.md's version section said, unqualified, that +# THE DRIFT THIS LOCKS. CLAUDE.md's version section said, unqualified, that # every user-facing merge must bump the version "in the same PR". The shipped # machinery says the opposite for one whole lane: skills/solve-fleet/workflow.js # FORBIDS every fleet solver from bumping, because N solvers cut off one base # all resolve the SAME next version and that duplicate edit auto-merges without # a conflict, silently losing a release. So the rule document convicted the # fleet PRs that the tooling had just told to stay unbumped — and the review -# convention lens, which cites AGENTS.md verbatim, filed that contradiction as a +# convention lens, which cites CLAUDE.md verbatim, filed that contradiction as a # blocker on a compliant PR (#472). Fixing the prose alone would re-rot: this # section pins the rule and the machinery to each other, so a future edit to # either half that leaves the other behind is a red test, not a stale sentence. @@ -1954,53 +1954,53 @@ echo "== T12: the version-bump contract — rule doc and machinery, locked in bo # with B. Opening one line lower lets the end anchor be a plain `^## `, which # closes on EVERY sibling section. # -# STATED PLAINLY, because the scoping is weaker than it looks: AGENTS.md carries +# STATED PLAINLY, because the scoping is weaker than it looks: CLAUDE.md carries # exactly ONE level-2 heading today, so this range still runs to end-of-file and # the anchoring buys nothing until a sibling section is added — it is insurance, # not a property of the file as it stands. The start anchor is the invariant # sentence T12.2a/T12.2b already pin; reword it and all eleven in-section # assertions go red together, loudly, rather than passing over an empty slice. -AGENTS_SECTION_START='^\*\*Every user-facing change' -AGENTS_SECTION_END='^## ' +CLAUDE_SECTION_START='^\*\*Every user-facing change' +CLAUDE_SECTION_END='^## ' -# --- the rule half: what AGENTS.md must say ------------------------------- -assert_grep "$AGENTS_MD" '^## Bump version EVERYWHERE before merge \(MANDATORY\)$' \ - "T12.1 AGENTS.md still carries the version-bump section heading" -assert_in_section "$AGENTS_MD" "$AGENTS_SECTION_START" "$AGENTS_SECTION_END" \ +# --- the rule half: what CLAUDE.md must say ------------------------------- +assert_grep "$CLAUDE_MD" '^## Bump version EVERYWHERE before merge \(MANDATORY\)$' \ + "T12.1 CLAUDE.md still carries the version-bump section heading" +assert_in_section "$CLAUDE_MD" "$CLAUDE_SECTION_START" "$CLAUDE_SECTION_END" \ 'landing commit' \ "T12.2a the invariant is scoped to the LANDING commit, not to every PR" -assert_in_section "$AGENTS_MD" "$AGENTS_SECTION_START" "$AGENTS_SECTION_END" \ +assert_in_section "$CLAUDE_MD" "$CLAUDE_SECTION_START" "$CLAUDE_SECTION_END" \ '(project )?version advanced|advance the (project )?version' \ "T12.2b the invariant is that the version ADVANCED on main" -assert_in_section "$AGENTS_MD" "$AGENTS_SECTION_START" "$AGENTS_SECTION_END" \ +assert_in_section "$CLAUDE_MD" "$CLAUDE_SECTION_START" "$CLAUDE_SECTION_END" \ '`/goal`' \ "T12.3a the /goal lane is named" -assert_in_section "$AGENTS_MD" "$AGENTS_SECTION_START" "$AGENTS_SECTION_END" \ +assert_in_section "$CLAUDE_MD" "$CLAUDE_SECTION_START" "$CLAUDE_SECTION_END" \ '`/solve`.*`/turbo`.*fleet' \ "T12.3b the /solve + /turbo fleet lane is named" -assert_in_section "$AGENTS_MD" "$AGENTS_SECTION_START" "$AGENTS_SECTION_END" \ +assert_in_section "$CLAUDE_MD" "$CLAUDE_SECTION_START" "$CLAUDE_SECTION_END" \ '[Hh]and-authored' \ "T12.3c the hand-authored lane is named" -assert_in_section "$AGENTS_MD" "$AGENTS_SECTION_START" "$AGENTS_SECTION_END" \ +assert_in_section "$CLAUDE_MD" "$CLAUDE_SECTION_START" "$CLAUDE_SECTION_END" \ 'fleet PR whose diff carries no version surface is compliant' \ "T12.4 the fleet carve-out is explicit — an unbumped fleet PR is COMPLIANT" -assert_in_section "$AGENTS_MD" "$AGENTS_SECTION_START" "$AGENTS_SECTION_END" \ +assert_in_section "$CLAUDE_MD" "$CLAUDE_SECTION_START" "$CLAUDE_SECTION_END" \ 'skills/solve-fleet/workflow\.js' \ "T12.4b the carve-out names the file that forbids the solver from bumping" -assert_in_section "$AGENTS_MD" "$AGENTS_SECTION_START" "$AGENTS_SECTION_END" \ +assert_in_section "$CLAUDE_MD" "$CLAUDE_SECTION_START" "$CLAUDE_SECTION_END" \ 'plugins/uberdev/lib/bump-version\.sh' \ "T12.5 the bump mechanism is named by path" # Anchored to the numbered-list-item FORM, not a bare path substring: both test # paths also appear in the local-verification bullet further down the section, # so a substring match kept passing after the two surface entries themselves # were deleted — a label ("listed as a surface") wider than its predicate. -assert_in_section "$AGENTS_MD" "$AGENTS_SECTION_START" "$AGENTS_SECTION_END" \ +assert_in_section "$CLAUDE_MD" "$CLAUDE_SECTION_START" "$CLAUDE_SECTION_END" \ '^[0-9]+\. \*\*`tests/goal\.test\.sh`\*\*' \ "T12.5b the CI release-ratchet lock tests/goal.test.sh is still a numbered surface-list entry" -assert_in_section "$AGENTS_MD" "$AGENTS_SECTION_START" "$AGENTS_SECTION_END" \ +assert_in_section "$CLAUDE_MD" "$CLAUDE_SECTION_START" "$CLAUDE_SECTION_END" \ '^[0-9]+\. \*\*`tests/solve-claim\.test\.sh`\*\*' \ "T12.5c the CI release-ratchet lock tests/solve-claim.test.sh is still a numbered surface-list entry" -assert_in_section "$AGENTS_MD" "$AGENTS_SECTION_START" "$AGENTS_SECTION_END" \ +assert_in_section "$CLAUDE_MD" "$CLAUDE_SECTION_START" "$CLAUDE_SECTION_END" \ 'No exception' \ "T12.5d the no-exception clause survives the rewrite" @@ -2041,15 +2041,15 @@ assert_grep "$GOAL_WATCH_SH" '_uberdev_goal_ensure_version_bump' \ "T12.7 the /goal watch lane still calls the version-bump guarantor" # --- negatives: the retired claims must not come back --------------------- -assert_absent_fixed "$AGENTS_MD" 'MUST bump the version in every location below' \ +assert_absent_fixed "$CLAUDE_MD" 'MUST bump the version in every location below' \ "T12.9 the unqualified every-PR mandate (the sentence #472 was filed against) is gone" -assert_absent_fixed "$AGENTS_MD" 'single-escaped' \ +assert_absent_fixed "$CLAUDE_MD" 'single-escaped' \ "T12.10a the stale single-escaped regex-form description is gone (post-#231 the locks are one assert_version_bump arg)" -assert_absent_fixed "$AGENTS_MD" 'double-escaped' \ +assert_absent_fixed "$CLAUDE_MD" 'double-escaped' \ "T12.10b the stale double-escaped regex-form description is gone" -assert_absent_fixed "$AGENTS_MD" 'Update all seven locations above' \ +assert_absent_fixed "$CLAUDE_MD" 'Update all seven locations above' \ "T12.10c the 'seven locations in one commit' claim is gone (only six are files)" -assert_absent_fixed "$AGENTS_MD" "Codex's auto-update" \ +assert_absent_fixed "$CLAUDE_MD" "Codex's auto-update" \ "T12.10d the retired Codex auto-update rationale is gone (#381)" # Shipped-plugin pointers must not send a reader to the gitignored CLAUDE.md @@ -2098,8 +2098,8 @@ else fi fi -assert_grep "$BUMP_VERSION_SH" 'AGENTS\.md' \ - "T12.12 bump-version.sh's checklist comment names AGENTS.md as the documented ritual" +assert_grep "$BUMP_VERSION_SH" 'CLAUDE\.md' \ + "T12.12 bump-version.sh's checklist comment names CLAUDE.md as the documented ritual" assert_absent_fixed "$STRUCTURAL_LIB" 'Codex plugin.json' \ "T12.13 assert_version_bump's doc comment no longer claims a retired Codex manifest surface" assert_absent_fixed "$STRUCTURAL_LIB" 'all five manifest surfaces' \ diff --git a/tests/goal.test.sh b/tests/goal.test.sh index 5acf1037..1d65735c 100755 --- a/tests/goal.test.sh +++ b/tests/goal.test.sh @@ -505,8 +505,8 @@ assert_no_grep "$GOAL_LIB" '\bbash -c' "G19.no assert_grep "$GOAL_CMD" '--i-know-what-im-doing' "G19.r12-mentioned-once" echo -echo "== G20: version bump locked (0.56.0) ==" -assert_version_bump "$REPO_ROOT" "0.56.0" +echo "== G20: version bump locked (0.56.1) ==" +assert_version_bump "$REPO_ROOT" "0.56.1" assert_no_grep "$REPO_ROOT/tests/solve-claim.test.sh" '0\.30\.0' "G20.solve-claim-no-old-version" assert_grep "$GOAL_P0" 'uberdev_dispatch_resolve_env' "G20b.phase0-wires-resolve-env (#175 SSOT anchor)" diff --git a/tests/solve-claim.test.sh b/tests/solve-claim.test.sh index 34412b2f..e78215e8 100755 --- a/tests/solve-claim.test.sh +++ b/tests/solve-claim.test.sh @@ -46,8 +46,8 @@ source "$REPO_ROOT/tests/_lib_assert_structural.sh" || { echo "FATAL: _lib_asser # Both lines below are read by bump-version.sh as literal anchors. The echo text # and the assert_version_bump argument must carry the CURRENT version, and both # must be bumped together every release. -echo "== Version bump 0.55.1 -> 0.56.0 propagated ==" -assert_version_bump "$REPO_ROOT" "0.56.0" +echo "== Version bump 0.56.0 -> 0.56.1 propagated ==" +assert_version_bump "$REPO_ROOT" "0.56.1" # --- #123 B1: closing-keyword regex left-anchor ------------------------------- # Kept because it EXECUTES the regex rather than only asserting its presence,