From beed000acae07ba4556094538ceafab369b2ad4b Mon Sep 17 00:00:00 2001 From: SUaDtL Date: Sun, 2 Aug 2026 22:48:46 -0400 Subject: [PATCH 1/3] test(statusline): isolate palette fallback from git state The fallback assertion compares whole renders, so the bounded dirty probe could change an unrelated branch marker between calls. Pin that probe to keep the test focused on palette compatibility. --- plugins/ca/hooks/tests/test_colorlib.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/plugins/ca/hooks/tests/test_colorlib.py b/plugins/ca/hooks/tests/test_colorlib.py index 009590f0..46eea726 100644 --- a/plugins/ca/hooks/tests/test_colorlib.py +++ b/plugins/ca/hooks/tests/test_colorlib.py @@ -241,18 +241,19 @@ def test_failed_custom_theme_projects_effective_violet_and_legacy_bytes(self): with open(cases["oversized"], "wb") as handle: handle.write(b" " * (_colorlib.MAX_THEME_BYTES + 1)) - with mock.patch.dict(os.environ, {"CODEARBITER_THEME": "violet"}): - violet = sl.render(payload) - - for label, path in cases.items(): - with self.subTest(case=label), mock.patch.dict( - os.environ, {"CODEARBITER_THEME": "custom", - "CODEARBITER_THEME_FILE": path}): - rendered = sl.render(payload) - self.assertEqual(rendered, violet) - self.assertEqual(sl._colorlib.ACTIVE_THEME_NAME, "violet") - self.assertIn(sl.fg(90, 60, 150), rendered) - self.assertIn(sl.fg(170, 110, 240), rendered) + with mock.patch.object(sl, "git_dirty", return_value=True): + with mock.patch.dict(os.environ, {"CODEARBITER_THEME": "violet"}): + violet = sl.render(payload) + + for label, path in cases.items(): + with self.subTest(case=label), mock.patch.dict( + os.environ, {"CODEARBITER_THEME": "custom", + "CODEARBITER_THEME_FILE": path}): + rendered = sl.render(payload) + self.assertEqual(rendered, violet) + self.assertEqual(sl._colorlib.ACTIVE_THEME_NAME, "violet") + self.assertIn(sl.fg(90, 60, 150), rendered) + self.assertIn(sl.fg(170, 110, 240), rendered) def test_valid_partial_custom_keeps_custom_as_effective_theme(self): with tempfile.TemporaryDirectory() as tmp: From f8b0154af625725ee64b8c22366ccba9f0b41b59 Mon Sep 17 00:00:00 2001 From: SUaDtL Date: Sun, 2 Aug 2026 22:51:57 -0400 Subject: [PATCH 2/3] fix(site): align guarantee cards Starlight's sibling flow spacing adds block-start margin to later cards, creating a staggered row. Reset that margin at the card boundary so grid gap remains the only inter-card spacing. CHANGELOG: Align guarantee cards across responsive layouts. --- site/src/styles/landing.css | 1 + site/test/landing/landing-page.test.ts | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/site/src/styles/landing.css b/site/src/styles/landing.css index eac99172..60fa53ea 100644 --- a/site/src/styles/landing.css +++ b/site/src/styles/landing.css @@ -492,6 +492,7 @@ ca-splash-docs { .ca-feature { position: relative; + margin-block-start: 0; padding: var(--ca-space-6); } diff --git a/site/test/landing/landing-page.test.ts b/site/test/landing/landing-page.test.ts index a2242daf..49f40f0a 100644 --- a/site/test/landing/landing-page.test.ts +++ b/site/test/landing/landing-page.test.ts @@ -183,6 +183,12 @@ describe("first-class product splash", () => { expect(indexMdx).toContain("./guides/uninstalling/"); }); + it("keeps every guarantee card aligned despite Starlight's sibling flow spacing", () => { + expect(landingCss).toMatch( + /\.ca-feature\s*\{[^}]*margin-block-start:\s*0;/s, + ); + }); + it("uses page-relative internal links instead of a hardcoded deployment base", () => { expect(indexMdx).not.toMatch(/href="\/codeArbiter/); expect(indexMdx).toMatch(/href="\.\/getting-started\/install\//); From 6f5e6407619e1171f1c67b4183c5640ba867d61c Mon Sep 17 00:00:00 2001 From: SUaDtL Date: Mon, 3 Aug 2026 02:46:36 -0400 Subject: [PATCH 3/3] fix(ci): restore fresh-clone hook verification Fresh CI runners could not resolve a feature-branch-only historical SHA, while repeated render tests sampled a latency-bounded Git probe between comparisons. Pin a reachable byte-identical baseline, isolate the live probe in test fixtures, and advance the shipped CA payload version. CHANGELOG: Restore cross-platform hook CI and stable statusline regression checks. --- .codearbiter/.provenance/release-targets.json | 4 +-- .github/scripts/test_release_trace.py | 33 ++++++++++++------- CHANGELOG.md | 12 +++++++ README.md | 2 +- plugins/ca/.claude-plugin/plugin.json | 2 +- plugins/ca/hooks/tests/test_colorlib.py | 1 + plugins/ca/hooks/tests/test_statusline.py | 5 +-- 7 files changed, 41 insertions(+), 18 deletions(-) diff --git a/.codearbiter/.provenance/release-targets.json b/.codearbiter/.provenance/release-targets.json index 8c369660..c08a874c 100644 --- a/.codearbiter/.provenance/release-targets.json +++ b/.codearbiter/.provenance/release-targets.json @@ -4,7 +4,7 @@ "entries": [ { "drift_trigger": true, - "hash": "a39e18a12f1a3aefaebd5ac80b5519711d6aba84", + "hash": "7933577b4e8985942aed6caf2f859c121c57f7d0", "path": "CHANGELOG.md" }, { @@ -64,7 +64,7 @@ }, { "drift_trigger": true, - "hash": "8c98f20f9e4de1cdec10d6f99922e520347a3ba9", + "hash": "f963449c0e51f52a78ee77afa03315471dae0be7", "path": "plugins/ca/.claude-plugin/plugin.json" }, { diff --git a/.github/scripts/test_release_trace.py b/.github/scripts/test_release_trace.py index d967ffe0..5cfa6da6 100644 --- a/.github/scripts/test_release_trace.py +++ b/.github/scripts/test_release_trace.py @@ -27,14 +27,14 @@ two-manifest ca-pi shape, the three behaviors most likely to drift in a migration. -Pre-change SHA (T-27b): `6a903e6` — the parent of `0664506` (the commit that -performed the mechanism split), i.e. the last commit at which -`.github/scripts/_releaselib.py` was still the ORIGINAL self-contained -module. Chosen over "origin/main's copy" because origin/main moves and a -SHA does not; pinning to the immediate pre-split commit is the tightest, -least-ambiguous "the module as it stood the moment before this migration -began" reference the spec's `git show :...` instruction -asks for. +Pre-change SHA (T-27b): `469c2fb8` — the parent of `8ee5fe11` (the squash +merge that performed the mechanism split), i.e. the last reachable main +commit at which `.github/scripts/_releaselib.py` was still the ORIGINAL +self-contained module. Its module blob is byte-identical to the abandoned +feature-branch parent originally used here. Chosen over "origin/main's copy" +because origin/main moves and a SHA does not; pinning to the reachable +pre-merge commit is the tightest fresh-clone-safe reference the spec's +`git show :...` instruction asks for. Honest limit (stated once here, per the spec's own wording, rather than repeated at every call site): `.github/scripts/_releaselib.py` at the @@ -151,9 +151,9 @@ REPO_ROOT = os.path.dirname(os.path.dirname(HERE)) FIXTURE_DIR = os.path.join(HERE, "fixtures", "release-trace") -# T-27b: the parent of 0664506 (the mechanism-split commit) — see module -# docstring for why this SHA rather than "origin/main's copy" was chosen. -PRE_CHANGE_SHA = "6a903e6" +# T-27b: the parent of 8ee5fe11 (the mechanism-split squash merge) — see +# the module docstring for why this reachable SHA was chosen. +PRE_CHANGE_SHA = "469c2fb8" CORE_RELEASELIB_PATH = os.path.join(REPO_ROOT, "core", "pysrc", "_releaselib.py") SHIM_RELEASELIB_PATH = os.path.join(REPO_ROOT, ".github", "scripts", "_releaselib.py") @@ -182,7 +182,7 @@ def setUpModule(): if not has_commit or not has_tags: missing = [] if not has_commit: - missing.append(f"commit {PRE_CHANGE_SHA} is unreachable (shallow history)") + missing.append(f"commit {PRE_CHANGE_SHA} is unreachable from this checkout") if not has_tags: missing.append("no tags are present") raise RuntimeError( @@ -429,6 +429,15 @@ def test_old_lane_loads_the_pinned_pre_change_module(self): "ca-sandbox": "ca-sandbox-v", "ca-pi": "ca-pi-v"}) self.assertTrue(callable(self.old_lane.last_tag_select)) + def test_pinned_pre_change_commit_is_reachable_from_head(self): + result = subprocess.run( + ["git", "merge-base", "--is-ancestor", PRE_CHANGE_SHA, "HEAD"], + cwd=REPO_ROOT, capture_output=True, text=True, timeout=30) + self.assertEqual( + result.returncode, 0, + f"{PRE_CHANGE_SHA} is not reachable from HEAD; a fresh full-history " + "checkout cannot load the pinned pre-change module") + def test_old_lane_loads_a_genuinely_historical_snapshot(self): # Proves this is really pinned to git history and not accidentally # reading the live (now-converted) shim: the pre-change source must diff --git a/CHANGELOG.md b/CHANGELOG.md index a39e18a1..7933577b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,18 @@ predate the plugin rewrite and are grouped by date. ## [Unreleased] +## [2.11.1] — 2026-08-03 + +### Fixed + +- Restored fresh-clone release-trace verification by pinning its historical + reference to the reachable pre-migration commit with the same release-library + bytes. +- Stabilized repeated statusline-render tests by isolating their unrelated + repository-dirty probes. +- Kept the landing page's guarantee cards aligned by resetting inherited + sibling-flow spacing at the card boundary. + ## [2.11.0] — 2026-07-31 ### Added diff --git a/README.md b/README.md index f565045b..8ea04715 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ project context. You decide. codeArbiter enforces. Claude Code plugin Codex plugin Pi Feature Forge preview -version 2.11.0 +version 2.11.1 commands skills agents diff --git a/plugins/ca/.claude-plugin/plugin.json b/plugins/ca/.claude-plugin/plugin.json index 8c98f20f..f963449c 100644 --- a/plugins/ca/.claude-plugin/plugin.json +++ b/plugins/ca/.claude-plugin/plugin.json @@ -2,7 +2,7 @@ "name": "ca", "displayName": "codeArbiter", "description": "Orchestration layer for Claude Code. Routes every intent through gated skills and reviewer agents, drives spec-driven TDD, mechanically enforces the commit and audit-trail gates, decides via SMARTS, and keeps an append-only audit trail. Requires Python 3 on PATH. Dormant until you opt a repo in; run /ca:init to activate.", - "version": "2.11.0", + "version": "2.11.1", "author": { "name": "arbiterForge" }, "license": "AGPL-3.0-only", "homepage": "https://github.com/arbiterForge/codeArbiter", diff --git a/plugins/ca/hooks/tests/test_colorlib.py b/plugins/ca/hooks/tests/test_colorlib.py index 46eea726..8b0765c1 100644 --- a/plugins/ca/hooks/tests/test_colorlib.py +++ b/plugins/ca/hooks/tests/test_colorlib.py @@ -323,6 +323,7 @@ def counted_read(path): reads += 1 return real_read(path) sl._colorlib._read_custom = counted_read +sl.git_dirty = lambda _root: True out = sl.render(payload) again = sl.render(payload) if reads != 2: diff --git a/plugins/ca/hooks/tests/test_statusline.py b/plugins/ca/hooks/tests/test_statusline.py index c9af1d73..61ce561b 100644 --- a/plugins/ca/hooks/tests/test_statusline.py +++ b/plugins/ca/hooks/tests/test_statusline.py @@ -825,8 +825,9 @@ def test_render_is_deterministic_for_same_input(self): "context_window_size": 200000}, "cost": {"total_cost_usd": 1.23}, }) - a = sl.render(payload) - b = sl.render(payload) + with mock.patch.object(sl, "git_dirty", return_value=True): + a = sl.render(payload) + b = sl.render(payload) self.assertEqual(a, b) def test_ledger_functions_reachable_via_statusline(self):